From 21ef7e07a6969fe2cb74c1ef9ab7a1d557c04c3c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 6 Apr 2022 15:40:09 -0700 Subject: [PATCH 1/4] Code fix to add DisableRuntimeMarshalling when required Implement code fix to provide the DisableRuntimeMarshalling attribute when a P/Invoke requires it. Update tool versions to get required bugfixes --- eng/Versions.props | 12 +- ...DisableRuntimeMarshallingAttributeFixer.cs | 80 +++++++++ .../GeneratorDiagnostics.cs | 10 +- .../LibraryImportGenerator.cs | 2 +- .../IGeneratorDiagnostics.cs | 31 ++-- ...ributedMarshallingModelGeneratorFactory.cs | 7 +- .../Marshalling/MarshallingGenerator.cs | 3 + ...leRuntimeMarshallingAttributeFixerTests.cs | 165 ++++++++++++++++++ 8 files changed, 289 insertions(+), 21 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs diff --git a/eng/Versions.props b/eng/Versions.props index a1fb1fb08fa522..e7793554f2910c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -33,16 +33,16 @@ 3.3.3 - 4.2.0-2.22128.1 - 4.2.0-2.22128.1 - 4.2.0-2.22128.1 + 4.3.0-1.22206.2 + 4.3.0-1.22206.2 + 4.3.0-1.22206.2 7.0.0-preview1.22166.1 - 4.2.0-2.22128.1 + 4.3.0-1.22206.2 - 4.2.0-2.22128.1 + 4.3.0-1.22206.2 2.0.0-alpha.1.21525.11 @@ -164,7 +164,7 @@ 4.12.0 2.14.3 7.0.100-preview.3.22151.18 - 1.1.2-beta1.22122.4 + 1.1.2-beta1.22205.2 7.0.0-preview-20220316.2 diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs new file mode 100644 index 00000000000000..341e4d9943ed58 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; + +namespace Microsoft.Interop.Analyzers +{ + [ExportCodeFixProvider(LanguageNames.CSharp), Shared] + public class AddDisableRuntimeMarshallingAttributeFixer : CodeFixProvider + { + private const string EquivalenceKey = nameof(AddDisableRuntimeMarshallingAttributeFixer); + + public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(GeneratorDiagnostics.Ids.TypeNotSupported); + + // TODO: Write a custom fix all provider + public override FixAllProvider? GetFixAllProvider() => null; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + List fixedDiagnostics = new(context.Diagnostics.Where(IsRequiresDiableRuntimeMarshallingDiagnostic)); + + if (fixedDiagnostics.Count > 0) + { + context.RegisterCodeFix( + CodeAction.Create( + "Add DisableRuntimeMarshallingAttribute to the assembly.", + ct => AddDisableRuntimeMarshallingAttributeApplicationToProject(context.Document.Project, ct), + EquivalenceKey), + fixedDiagnostics); + } + + return Task.CompletedTask; + + static bool IsRequiresDiableRuntimeMarshallingDiagnostic(Diagnostic diagnostic) + { + return diagnostic.Properties.ContainsKey(GeneratorDiagnosticProperties.AddDisableRuntimeMarshallingAttribute); + } + } + + private async Task AddDisableRuntimeMarshallingAttributeApplicationToProject(Project project, CancellationToken cancellationToken) + { + Document? assemblyInfo = project.Documents.FirstOrDefault(IsPropertiesAssemblyInfo); + + if (assemblyInfo is null) + { + assemblyInfo = project.AddDocument("AssemblyInfo.cs", "", folders: new[] { "Properties" }); + } + + DocumentEditor editor = await DocumentEditor.CreateAsync(assemblyInfo, cancellationToken).ConfigureAwait(false); + + var syntaxRoot = await assemblyInfo.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + editor.ReplaceNode( + syntaxRoot, + editor.Generator.AddAttributes( + syntaxRoot, + editor.Generator.Attribute(editor.Generator.DottedName(TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute)))); + + return editor.GetChangedDocument().Project.Solution; + + static bool IsPropertiesAssemblyInfo(Document document) + { + return document.Name == "AssemblyInfo.cs" + && document.Folders.Count == 1 + && document.Folders[0] == "Properties"; + } + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs index 56589707b9f68a..d6466545fd290a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs @@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; namespace Microsoft.Interop @@ -226,7 +227,8 @@ public void ReportConfigurationNotSupported( public void ReportMarshallingNotSupported( MethodDeclarationSyntax method, TypePositionInfo info, - string? notSupportedDetails) + string? notSupportedDetails, + ImmutableDictionary diagnosticProperties) { Location diagnosticLocation = Location.None; string elementName = string.Empty; @@ -252,6 +254,7 @@ public void ReportMarshallingNotSupported( _diagnostics.Add( diagnosticLocation.CreateDiagnostic( GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails, + diagnosticProperties, notSupportedDetails!, elementName)); } @@ -260,6 +263,7 @@ public void ReportMarshallingNotSupported( _diagnostics.Add( diagnosticLocation.CreateDiagnostic( GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails, + diagnosticProperties, notSupportedDetails!, elementName)); } @@ -274,6 +278,7 @@ public void ReportMarshallingNotSupported( _diagnostics.Add( diagnosticLocation.CreateDiagnostic( GeneratorDiagnostics.ReturnConfigurationNotSupported, + diagnosticProperties, nameof(System.Runtime.InteropServices.MarshalAsAttribute), elementName)); } @@ -282,6 +287,7 @@ public void ReportMarshallingNotSupported( _diagnostics.Add( diagnosticLocation.CreateDiagnostic( GeneratorDiagnostics.ParameterConfigurationNotSupported, + diagnosticProperties, nameof(System.Runtime.InteropServices.MarshalAsAttribute), elementName)); } @@ -294,6 +300,7 @@ public void ReportMarshallingNotSupported( _diagnostics.Add( diagnosticLocation.CreateDiagnostic( GeneratorDiagnostics.ReturnTypeNotSupported, + diagnosticProperties, info.ManagedType.DiagnosticFormattedName, elementName)); } @@ -302,6 +309,7 @@ public void ReportMarshallingNotSupported( _diagnostics.Add( diagnosticLocation.CreateDiagnostic( GeneratorDiagnostics.ParameterTypeNotSupported, + diagnosticProperties, info.ManagedType.DiagnosticFormattedName, elementName)); } diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs index 1040ca2e450840..67c5805cf620ae 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs @@ -501,7 +501,7 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou pinvokeStub.LibraryImportData.SetLastError && !options.GenerateForwarders, (elementInfo, ex) => { - diagnostics.ReportMarshallingNotSupported(originalSyntax, elementInfo, ex.NotSupportedDetails); + diagnostics.ReportMarshallingNotSupported(originalSyntax, elementInfo, ex.NotSupportedDetails, ex.DiagnosticProperties ?? ImmutableDictionary.Empty); }, pinvokeStub.StubContext.GeneratorFactory); diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs index 3af27467e7ff0d..e91a12b4d18037 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs @@ -68,7 +68,7 @@ public static Diagnostic CreateDiagnostic( { IEnumerable locationsInSource = locations.Where(l => l.IsInSource); if (!locationsInSource.Any()) - return Diagnostic.Create(descriptor, Location.None, args); + return Diagnostic.Create(descriptor, Location.None, properties: properties, args); return Diagnostic.Create( descriptor, @@ -88,22 +88,24 @@ public static Diagnostic CreateDiagnostic( location: location.IsInSource ? location : Location.None, messageArgs: args); } + + public static Diagnostic CreateDiagnostic( + this Location location, + DiagnosticDescriptor descriptor, + ImmutableDictionary properties, + params object[] args) + { + return Diagnostic.Create( + descriptor, + location: location.IsInSource ? location : Location.None, + properties: properties, + messageArgs: args); + } } public interface IGeneratorDiagnostics { - /// - /// Report diagnostic for marshalling of a parameter/return that is not supported - /// - /// Method with the parameter/return - /// Type info for the parameter/return - /// [Optional] Specific reason for lack of support - void ReportMarshallingNotSupported( - MethodDeclarationSyntax method, - TypePositionInfo info, - string? notSupportedDetails); - /// /// Report diagnostic for configuration that is not supported by the DLL import source generator /// @@ -126,4 +128,9 @@ public static class IGeneratorDiagnosticsExtensions public static void ReportConfigurationNotSupported(this IGeneratorDiagnostics diagnostics, AttributeData attributeData, string configurationName) => diagnostics.ReportConfigurationNotSupported(attributeData, configurationName, null); } + + public class GeneratorDiagnosticProperties + { + public const string AddDisableRuntimeMarshallingAttribute = nameof(AddDisableRuntimeMarshallingAttribute); + } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs index f3aac5de6a7290..094cbd6564a9ef 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Collections.Immutable; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -14,6 +15,9 @@ namespace Microsoft.Interop public class AttributedMarshallingModelGeneratorFactory : IMarshallingGeneratorFactory { + private static readonly ImmutableDictionary AddDisableRuntimeMarshallingAttributeProperties = + ImmutableDictionary.Empty.Add(GeneratorDiagnosticProperties.AddDisableRuntimeMarshallingAttribute, GeneratorDiagnosticProperties.AddDisableRuntimeMarshallingAttribute); + private static readonly BlittableMarshaller s_blittable = new BlittableMarshaller(); private static readonly Forwarder s_forwarder = new Forwarder(); @@ -54,7 +58,8 @@ public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext conte UnmanagedBlittableMarshallingInfo or NativeMarshallingAttributeInfo when !Options.RuntimeMarshallingDisabled => throw new MarshallingNotSupportedException(info, context) { - NotSupportedDetails = Resources.RuntimeMarshallingMustBeDisabled + NotSupportedDetails = Resources.RuntimeMarshallingMustBeDisabled, + DiagnosticProperties = AddDisableRuntimeMarshallingAttributeProperties }, GeneratedNativeMarshallingAttributeInfo => s_forwarder, MissingSupportMarshallingInfo => s_forwarder, diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs index 65ef66ce0438b3..f2104a2d7f6d58 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -160,5 +161,7 @@ public MarshallingNotSupportedException(TypePositionInfo info, StubCodeContext c /// [Optional] Specific reason marshalling of the supplied type isn't supported. /// public string? NotSupportedDetails { get; init; } + + public ImmutableDictionary? DiagnosticProperties { get; init; } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs new file mode 100644 index 00000000000000..8f7bd04aff1ef3 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs @@ -0,0 +1,165 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing.Model; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.Interop.Analyzers; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.Interop; + +using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< + LibraryImportGenerator.UnitTests.AddDisableRuntimeMarshallingAttributeFixerTests.MockAnalyzer, + Microsoft.Interop.Analyzers.AddDisableRuntimeMarshallingAttributeFixer>; +using Xunit; +using System.IO; + +namespace LibraryImportGenerator.UnitTests +{ + public class AddDisableRuntimeMarshallingAttributeFixerTests + { + [Fact] + public static async Task Adds_NewFile_With_Attribute() + { + // Source will have CS8795 (Partial method must have an implementation) without generator run + var source = @" +using System.Runtime.InteropServices; +partial class Foo +{ + [LibraryImport(""Foo"")] + public static partial void {|CS8795:PInvoke|}(S {|#0:s|}); +} + +[NativeMarshalling(typeof(Native))] +struct S +{ +} + +[CustomTypeMarshaller(typeof(S))] +struct Native +{ + public Native(S s) {} + + public S ToManaged() => new S(); +} +"; + var expectedPropertiesFile = "[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling]" + Environment.NewLine; + + var diagnostic = VerifyCS.Diagnostic(GeneratorDiagnostics.Ids.TypeNotSupported).WithLocation(0).WithArguments("S", "s"); + await VerifyCodeFixAsync(source, propertiesFile: null, expectedPropertiesFile, diagnostic); + } + + [Fact] + public static async Task Appends_Attribute_To_Existing_AssemblyInfo_File() + { + var source = @" +using System.Runtime.InteropServices; +partial class Foo +{ + [LibraryImport(""Foo"")] + public static partial void {|CS8795:PInvoke|}(S {|#0:s|}); +} + +[NativeMarshalling(typeof(Native))] +struct S +{ +} + +[CustomTypeMarshaller(typeof(S))] +struct Native +{ + public Native(S s) {} + + public S ToManaged() => new S(); +} +"; + var propertiesFile = @" +using System.Reflection; + +[assembly: AssemblyMetadata(""MyMetadata"", ""Value"")] +"; + var expectedPropertiesFile = @" +using System.Reflection; + +[assembly: AssemblyMetadata(""MyMetadata"", ""Value"")] +[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling] +"; + + var diagnostic = VerifyCS.Diagnostic(GeneratorDiagnostics.Ids.TypeNotSupported).WithLocation(0).WithArguments("S", "s"); + await VerifyCodeFixAsync(source, propertiesFile, expectedPropertiesFile, diagnostic); + } + + private static async Task VerifyCodeFixAsync(string source, string? propertiesFile, string? expectedPropertiesFile, DiagnosticResult diagnostic) + { + var test = new Test(); + test.TestCode = source; + test.FixedCode = source; + test.BatchFixedCode = source; + test.ExpectedDiagnostics.Add(diagnostic); + if (propertiesFile is not null) + { + test.TestState.Sources.Add(($"{Test.FilePathPrefix}Properties{Path.DirectorySeparatorChar}AssemblyInfo.cs", propertiesFile)); + } + if (expectedPropertiesFile is not null) + { + test.FixedState.Sources.Add(($"{Test.FilePathPrefix}Properties{Path.DirectorySeparatorChar}AssemblyInfo.cs", expectedPropertiesFile)); + test.BatchFixedState.Sources.Add(($"{Test.FilePathPrefix}Properties{Path.DirectorySeparatorChar}AssemblyInfo.cs", expectedPropertiesFile)); + } + await test.RunAsync(); + } + + class Test : VerifyCS.Test + { + public const string FilePathPrefix = "/Project/"; + + protected override string DefaultFilePathPrefix => FilePathPrefix; + } + + // The Roslyn SDK doesn't provide a good test harness for testing a code fix that triggers + // on a source-generator-introduced diagnostic. This analyzer does a decent enough job of triggering + // the specific diagnostic in the right place for us to test the code fix. + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class MockAnalyzer : DiagnosticAnalyzer + { + private static readonly DiagnosticDescriptor AddDisableRuntimeMarshallingAttributeRule = GeneratorDiagnostics.ParameterTypeNotSupported; + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(AddDisableRuntimeMarshallingAttributeRule); + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.RegisterSymbolAction(context => + { + var symbol = (IParameterSymbol)context.Symbol; + + if (context.Symbol.ContainingAssembly.GetAttributes().Any(attr => attr.AttributeClass!.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute)) + { + return; + } + + if (symbol.ContainingSymbol is IMethodSymbol { IsStatic: true, IsPartialDefinition: true }) + { + context.ReportDiagnostic(context.Symbol.CreateDiagnostic( + AddDisableRuntimeMarshallingAttributeRule, + ImmutableDictionary.Empty + .Add( + GeneratorDiagnosticProperties.AddDisableRuntimeMarshallingAttribute, + GeneratorDiagnosticProperties.AddDisableRuntimeMarshallingAttribute), + symbol.Type.ToDisplayString(), symbol.Name)); + } + }, SymbolKind.Parameter); + } + } + } +} From 3588a62fa563392f535c9c3da5d89340655891fd Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 6 Apr 2022 16:08:32 -0700 Subject: [PATCH 2/4] Add static --- .../Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs index 341e4d9943ed58..43a16044b5210c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs @@ -48,7 +48,7 @@ static bool IsRequiresDiableRuntimeMarshallingDiagnostic(Diagnostic diagnostic) } } - private async Task AddDisableRuntimeMarshallingAttributeApplicationToProject(Project project, CancellationToken cancellationToken) + private static async Task AddDisableRuntimeMarshallingAttributeApplicationToProject(Project project, CancellationToken cancellationToken) { Document? assemblyInfo = project.Documents.FirstOrDefault(IsPropertiesAssemblyInfo); From d0937f45af41d729196669ff949017a41b254832 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 8 Apr 2022 16:44:28 -0700 Subject: [PATCH 3/4] PR Feedback --- .../AddDisableRuntimeMarshallingAttributeFixer.cs | 11 ++++++++--- .../Marshalling/MarshallingGenerator.cs | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs index 43a16044b5210c..2d224e9d30c71e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/AddDisableRuntimeMarshallingAttributeFixer.cs @@ -21,6 +21,9 @@ public class AddDisableRuntimeMarshallingAttributeFixer : CodeFixProvider { private const string EquivalenceKey = nameof(AddDisableRuntimeMarshallingAttributeFixer); + private const string PropertiesFolderName = "Properties"; + private const string AssemblyInfoFileName = "AssemblyInfo.cs"; + public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(GeneratorDiagnostics.Ids.TypeNotSupported); // TODO: Write a custom fix all provider @@ -54,7 +57,7 @@ private static async Task AddDisableRuntimeMarshallingAttributeApplica if (assemblyInfo is null) { - assemblyInfo = project.AddDocument("AssemblyInfo.cs", "", folders: new[] { "Properties" }); + assemblyInfo = project.AddDocument(AssemblyInfoFileName, "", folders: new[] { PropertiesFolderName }); } DocumentEditor editor = await DocumentEditor.CreateAsync(assemblyInfo, cancellationToken).ConfigureAwait(false); @@ -71,9 +74,11 @@ private static async Task AddDisableRuntimeMarshallingAttributeApplica static bool IsPropertiesAssemblyInfo(Document document) { - return document.Name == "AssemblyInfo.cs" + // We specifically want to match a file in the Properties folder with the provided name (AssemblyInfo.cs) to match other VS templates that add this file. + // We are very strict about this to ensure that we discover the correct file when it is already created and added to the project. + return document.Name == AssemblyInfoFileName && document.Folders.Count == 1 - && document.Folders[0] == "Properties"; + && document.Folders[0] == PropertiesFolderName; } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs index f2104a2d7f6d58..2f622da69344d5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs @@ -162,6 +162,9 @@ public MarshallingNotSupportedException(TypePositionInfo info, StubCodeContext c /// public string? NotSupportedDetails { get; init; } + /// + /// [Optional] Properties to attach to any diagnostic emitted due to this exception. + /// public ImmutableDictionary? DiagnosticProperties { get; init; } } } From 549da88ec135f76a910b2c9b4ad88abf58998f7c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 11 Apr 2022 15:43:45 -0700 Subject: [PATCH 4/4] Skip the generated code check for the new fixer and the associated mock analyzer --- .../AddDisableRuntimeMarshallingAttributeFixerTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs index 8f7bd04aff1ef3..c905bfa14ef04c 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs @@ -102,6 +102,9 @@ public Native(S s) {} private static async Task VerifyCodeFixAsync(string source, string? propertiesFile, string? expectedPropertiesFile, DiagnosticResult diagnostic) { var test = new Test(); + // We don't care about validating the settings for the MockAnalyzer and we're also hitting failures on Mono + // with this check in this case, so skip the check for now. + test.TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck; test.TestCode = source; test.FixedCode = source; test.BatchFixedCode = source;