From b1733e95c6d35b551fc8cf6fe04e2a0c287346dd Mon Sep 17 00:00:00 2001 From: Sophia Chen <sophia.s.chen@vanderbilt.edu> Date: Fri, 6 Dec 2024 17:23:02 -0800 Subject: [PATCH] Improved Diagnostics for error scenarios with authoring projects (#1863) * first commit * first commit * return instead of throw * dont hardcode version num * delete unused line --------- Co-authored-by: Sophia Chen <sophia.six.chen@gmail.com> Co-authored-by: Manodasan Wignarajah <mawign@microsoft.com> --- .../AnalyzerReleases.Shipped.md | 9 ++- .../CsWinRTDiagnosticStrings.Designer.cs | 18 +++++ .../CsWinRTDiagnosticStrings.resx | 73 ++++++++++++++++++- .../WinRT.SourceGenerator/Generator.cs | 10 ++- .../WinRT.SourceGenerator/WinRTRules.cs | 5 ++ src/cswinrt/main.cpp | 4 +- src/cswinrt/text_writer.h | 8 ++ 7 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md index 95bda0d96..82f5c6bee 100644 --- a/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md +++ b/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Shipped.md @@ -47,4 +47,11 @@ CsWinRT1029 | Usage | Warning | Class implements WinRT interfaces generated usin ### New Rules Rule ID | Category | Severity | Notes --------|----------|----------|------- -CsWinRT1030 | Usage | Warning | Project needs to be updated with `<AllowUnsafeBlocks>true</AllowUnsafeBlocks>` to allow generic interface code generation. +CsWinRT1030 | Usage | Warning | Project needs to be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' to allow generic interface code generation. + +## Release 2.2.1 + +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +CsWinRT1031 | Usage | Error | Source generator failed. \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs index 65d770159..9678479aa 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.Designer.cs @@ -573,6 +573,24 @@ internal static string RefParameterFound_Text { } } + /// <summary> + /// Looks up a localized string similar to Source generator failed. + /// </summary> + internal static string SourceGeneratorFailed_Brief { + get { + return ResourceManager.GetString("SourceGeneratorFailed_Brief", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to CsWinRT component authoring source generator 'WinRT.SourceGenerator' failed to generate WinMD and projection because of '{0}'. + /// </summary> + internal static string SourceGeneratorFailed_Text { + get { + return ResourceManager.GetString("SourceGeneratorFailed_Text", resourceCulture); + } + } + /// <summary> /// Looks up a localized string similar to Const field in struct. /// </summary> diff --git a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx index 6c1d7f141..58b027ef6 100644 --- a/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx +++ b/src/Authoring/WinRT.SourceGenerator/CsWinRTDiagnosticStrings.resx @@ -1,5 +1,64 @@ <?xml version="1.0" encoding="utf-8"?> <root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:element name="root" msdata:IsDataSet="true"> @@ -120,7 +179,7 @@ </data> <data name="BindableCustomPropertyClassNotMarkedPartial_Text" xml:space="preserve"> <value>Class '{0}' has attribute GeneratedBindableCustomProperty but it or a parent type isn't marked partial. Type and any parent types should be marked partial to allow source generation for trimming and AOT compatibility.</value> - </data> + </data> <data name="DisjointNamespaceRule_Brief" xml:space="preserve"> <value>Namespace is disjoint from main (winmd) namespace</value> </data> @@ -231,9 +290,6 @@ <data name="RefParameterFound_Brief" xml:space="preserve"> <value>Parameter passed by reference</value> </data> - <data name="RefParameterFound_Text" xml:space="preserve"> - <value>Method '{0}' has parameter '{1}' marked `ref`; reference parameters are not allowed in Windows Runtime</value> - </data> <data name="StructHasConstFieldRule_Brief" xml:space="preserve"> <value>Const field in struct</value> </data> @@ -292,4 +348,13 @@ <value>Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic: {2}.</value> <comment>{1} and {2} will be keywords (types) from DotNet</comment> </data> + <data name="RefParameterFound_Text" xml:space="preserve"> + <value>Method '{0}' has parameter '{1}' marked `ref`; reference parameters are not allowed in Windows Runtime</value> + </data> + <data name="SourceGeneratorFailed_Brief" xml:space="preserve"> + <value>Source generator failed</value> + </data> + <data name="SourceGeneratorFailed_Text" xml:space="preserve"> + <value>CsWinRT component authoring source generator 'WinRT.SourceGenerator' failed to generate WinMD and projection because of '{0}'</value> + </data> </root> \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator/Generator.cs b/src/Authoring/WinRT.SourceGenerator/Generator.cs index c2e159f77..cd7769c37 100644 --- a/src/Authoring/WinRT.SourceGenerator/Generator.cs +++ b/src/Authoring/WinRT.SourceGenerator/Generator.cs @@ -14,6 +14,7 @@ using System.Reflection.PortableExecutable; using System.Text; using System.Threading; +using WinRT.SourceGenerator; namespace Generator { @@ -91,12 +92,15 @@ private void GenerateSources() { using var cswinrtProcess = Process.Start(processInfo); Logger.Log(cswinrtProcess.StandardOutput.ReadToEnd()); - Logger.Log(cswinrtProcess.StandardError.ReadToEnd()); + var error = cswinrtProcess.StandardError.ReadToEnd(); + Logger.Log(error); cswinrtProcess.WaitForExit(); if (cswinrtProcess.ExitCode != 0) { - throw new Win32Exception(cswinrtProcess.ExitCode); + var diagnosticDescriptor = WinRTRules.SourceGeneratorFailed; + context.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, null, error)); + throw new Win32Exception(cswinrtProcess.ExitCode, error); } foreach (var file in Directory.GetFiles(outputDir, "*.cs", SearchOption.TopDirectoryOnly)) @@ -190,7 +194,7 @@ public void Generate() } Logger.Close(); Environment.ExitCode = -2; - throw; + return; } Logger.Log("Done"); diff --git a/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs b/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs index 5ab4a338f..ca54ee962 100644 --- a/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTRules.cs @@ -238,5 +238,10 @@ private static DiagnosticDescriptor MakeRule(string id, string title, string mes CsWinRTDiagnosticStrings.ClassImplementsOldProjection_Brief, CsWinRTDiagnosticStrings.ClassOldProjectionMultipleInstances_Text, false); + + public static DiagnosticDescriptor SourceGeneratorFailed = MakeRule( + "CsWinRT1031", + CsWinRTDiagnosticStrings.SourceGeneratorFailed_Brief, + CsWinRTDiagnosticStrings.SourceGeneratorFailed_Text); } } diff --git a/src/cswinrt/main.cpp b/src/cswinrt/main.cpp index 942d5bbf7..6496ce1d3 100644 --- a/src/cswinrt/main.cpp +++ b/src/cswinrt/main.cpp @@ -350,7 +350,7 @@ Where <spec> is one or more of: { writer console; console.write("error: '%' when processing %%%\n", e.what(), ns, currentType.empty() ? "" : ".", currentType); - console.flush_to_console(); + console.flush_to_console_error(); throw; } }); @@ -541,6 +541,8 @@ ComWrappersSupport.RegisterAuthoringMetadataTypeLookup(new Func<Type, Type>(GetM { w.write(" error: %\n", e.what()); result = 1; + w.flush_to_console_error(); + return result; } w.flush_to_console(); diff --git a/src/cswinrt/text_writer.h b/src/cswinrt/text_writer.h index ce7fee38a..cb70361a9 100644 --- a/src/cswinrt/text_writer.h +++ b/src/cswinrt/text_writer.h @@ -153,6 +153,14 @@ namespace cswinrt m_second.clear(); } + void flush_to_console_error() noexcept + { + fprintf(stderr, "%.*s", static_cast<int>(m_first.size()), m_first.data()); + fprintf(stderr, "%.*s", static_cast<int>(m_second.size()), m_second.data()); + m_first.clear(); + m_second.clear(); + } + void flush_to_file(std::string const& filename) { if (!file_equal(filename))