From eea9df29abd7b933f5793fdbb61f787344a4eb6a Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 23 Sep 2022 17:20:37 -0700 Subject: [PATCH 1/4] Directly pass along target framework kind and version instead of StubEnvironment to avoid rooting the compilation. Update all generators to follow suit and add a test in LibraryImportGenerator to validate that we don't keep the compilation alive. --- .../JSExportCodeGenerator.cs | 7 +-- .../JSImportGenerator/JSExportGenerator.cs | 34 +++--------- .../JSImportCodeGenerator.cs | 7 +-- .../JSImportGenerator/JSImportGenerator.cs | 31 ++--------- .../ComInterfaceGeneratorHelpers.cs | 54 +++++++++++++++++++ .../ConvertToLibraryImportAnalyzer.cs | 2 +- .../LibraryImportGenerator.cs | 44 ++++++--------- .../LibraryImportGenerator.csproj | 2 +- .../PInvokeStubCodeGenerator.cs | 16 +++--- .../ManagedToNativeStubCodeContext.cs | 10 ++-- .../StubEnvironment.cs | 28 +--------- .../IncrementalGenerationTests.cs | 47 ++++++++++++++++ 12 files changed, 149 insertions(+), 133 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs index 3c44d665748b5c..614bad043f15af 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs @@ -20,7 +20,8 @@ internal sealed class JSExportCodeGenerator : JSCodeGenerator private readonly JSSignatureContext _signatureContext; public JSExportCodeGenerator( - StubEnvironment environment, + TargetFramework targetFramework, + Version targetFrameworkVersion, ImmutableArray argTypes, JSExportData attributeData, JSSignatureContext signatureContext, @@ -28,13 +29,13 @@ public JSExportCodeGenerator( IMarshallingGeneratorFactory generatorFactory) { _signatureContext = signatureContext; - ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnIdentifier); + ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier); _context = new JSExportCodeContext(attributeData, innerContext); _marshallers = new BoundGenerators(argTypes, CreateGenerator); if (_marshallers.ManagedReturnMarshaller.Generator.UsesNativeIdentifier(_marshallers.ManagedReturnMarshaller.TypeInfo, null)) { // If we need a different native return identifier, then recreate the context with the correct identifier before we generate any code. - innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnNativeIdentifier); + innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnNativeIdentifier); _context = new JSExportCodeContext(attributeData, innerContext); _marshallers = new BoundGenerators(argTypes, CreateGenerator); } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index c0336378816730..d84440e0750870 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -17,33 +17,13 @@ namespace Microsoft.Interop.JavaScript public sealed class JSExportGenerator : IIncrementalGenerator { internal sealed record IncrementalStubGenerationContext( - StubEnvironment Environment, JSSignatureContext SignatureContext, ContainingSyntaxContext ContainingSyntaxContext, ContainingSyntax StubMethodSyntaxTemplate, MethodSignatureDiagnosticLocations DiagnosticLocation, JSExportData JSExportData, - MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> GeneratorFactoryKey, - ImmutableArray Diagnostics) - { - public bool Equals(IncrementalStubGenerationContext? other) - { - return other is not null - && StubEnvironment.AreCompilationSettingsEqual(Environment, other.Environment) - && SignatureContext.Equals(other.SignatureContext) - && ContainingSyntaxContext.Equals(other.ContainingSyntaxContext) - && StubMethodSyntaxTemplate.Equals(other.StubMethodSyntaxTemplate) - && JSExportData.Equals(other.JSExportData) - && DiagnosticLocation.Equals(DiagnosticLocation) - && GeneratorFactoryKey.Equals(other.GeneratorFactoryKey) - && Diagnostics.SequenceEqual(other.Diagnostics); - } - - public override int GetHashCode() - { - throw new UnreachableException(); - } - } + MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion, JSGeneratorOptions)> GeneratorFactoryKey, + ImmutableArray Diagnostics); public static class StepNames { @@ -119,9 +99,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) static (data, ct) => CalculateStubInformation(data.Syntax, data.Symbol, data.Environment, data.Options, ct) ) .WithTrackingName(StepNames.CalculateStubInformation) - .Combine(stubOptions) .Select( - static (data, ct) => GenerateSource(data.Left, data.Right) + static (data, ct) => GenerateSource(data) ) .WithComparer(Comparers.GeneratedSyntax) .WithTrackingName(StepNames.GenerateSingleStub); @@ -215,7 +194,6 @@ private static IncrementalStubGenerationContext CalculateStubInformation( var methodSyntaxTemplate = new ContainingSyntax(originalSyntax.Modifiers.StripTriviaFromTokens(), SyntaxKind.MethodDeclaration, originalSyntax.Identifier, originalSyntax.TypeParameterList); return new IncrementalStubGenerationContext( - environment, signatureContext, containingTypeContext, methodSyntaxTemplate, @@ -232,14 +210,14 @@ private static IncrementalStubGenerationContext CalculateStubInformation( } private static (MemberDeclarationSyntax, ImmutableArray) GenerateSource( - IncrementalStubGenerationContext incrementalContext, - JSGeneratorOptions options) + IncrementalStubGenerationContext incrementalContext) { var diagnostics = new GeneratorDiagnostics(); // Generate stub code var stubGenerator = new JSExportCodeGenerator( - incrementalContext.Environment, + incrementalContext.GeneratorFactoryKey.Key.TargetFramework, + incrementalContext.GeneratorFactoryKey.Key.TargetFrameworkVersion, incrementalContext.SignatureContext.SignatureContext.ElementTypeInformation, incrementalContext.JSExportData, incrementalContext.SignatureContext, diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportCodeGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportCodeGenerator.cs index b7c1a324b2c477..1f1ebdf81b626c 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportCodeGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportCodeGenerator.cs @@ -27,7 +27,8 @@ internal sealed class JSImportCodeGenerator : JSCodeGenerator private readonly JSSignatureContext _signatureContext; public JSImportCodeGenerator( - StubEnvironment environment, + TargetFramework targetFramework, + Version targetFrameworkVersion, ImmutableArray argTypes, JSImportData attributeData, JSSignatureContext signatureContext, @@ -35,13 +36,13 @@ public JSImportCodeGenerator( IMarshallingGeneratorFactory generatorFactory) { _signatureContext = signatureContext; - ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnIdentifier); + ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier); _context = new JSImportCodeContext(attributeData, innerContext); _marshallers = new BoundGenerators(argTypes, CreateGenerator); if (_marshallers.ManagedReturnMarshaller.Generator.UsesNativeIdentifier(_marshallers.ManagedReturnMarshaller.TypeInfo, null)) { // If we need a different native return identifier, then recreate the context with the correct identifier before we generate any code. - innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnNativeIdentifier); + innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnNativeIdentifier); _context = new JSImportCodeContext(attributeData, innerContext); _marshallers = new BoundGenerators(argTypes, CreateGenerator); } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs index 0ce77445a85a8b..6aed61fe5dc117 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs @@ -2,12 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using System.Runtime.InteropServices; -using System.Text; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -22,33 +19,13 @@ namespace Microsoft.Interop.JavaScript public sealed class JSImportGenerator : IIncrementalGenerator { internal sealed record IncrementalStubGenerationContext( - StubEnvironment Environment, JSSignatureContext SignatureContext, ContainingSyntaxContext ContainingSyntaxContext, ContainingSyntax StubMethodSyntaxTemplate, MethodSignatureDiagnosticLocations DiagnosticLocation, JSImportData JSImportData, - MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> GeneratorFactoryKey, - ImmutableArray Diagnostics) - { - public bool Equals(IncrementalStubGenerationContext? other) - { - return other is not null - && StubEnvironment.AreCompilationSettingsEqual(Environment, other.Environment) - && SignatureContext.Equals(other.SignatureContext) - && ContainingSyntaxContext.Equals(other.ContainingSyntaxContext) - && StubMethodSyntaxTemplate.Equals(other.StubMethodSyntaxTemplate) - && JSImportData.Equals(other.JSImportData) - && DiagnosticLocation.Equals(DiagnosticLocation) - && GeneratorFactoryKey.Equals(other.GeneratorFactoryKey) - && Diagnostics.SequenceEqual(other.Diagnostics); - } - - public override int GetHashCode() - { - throw new UnreachableException(); - } - } + MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion, JSGeneratorOptions)> GeneratorFactoryKey, + ImmutableArray Diagnostics); public static class StepNames { @@ -228,7 +205,6 @@ private static IncrementalStubGenerationContext CalculateStubInformation( var methodSyntaxTemplate = new ContainingSyntax(originalSyntax.Modifiers.StripTriviaFromTokens(), SyntaxKind.MethodDeclaration, originalSyntax.Identifier, originalSyntax.TypeParameterList); return new IncrementalStubGenerationContext( - environment, signatureContext, containingTypeContext, methodSyntaxTemplate, @@ -253,7 +229,8 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou // Generate stub code var stubGenerator = new JSImportCodeGenerator( - incrementalContext.Environment, + incrementalContext.GeneratorFactoryKey.Key.TargetFramework, + incrementalContext.GeneratorFactoryKey.Key.TargetFrameworkVersion, incrementalContext.SignatureContext.SignatureContext.ElementTypeInformation, incrementalContext.JSImportData, incrementalContext.SignatureContext, diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs new file mode 100644 index 00000000000000..f9f0bf684ff821 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs @@ -0,0 +1,54 @@ +// 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.Linq; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Interop +{ + internal static class ComInterfaceGeneratorHelpers + { + public static MarshallingGeneratorFactoryKey<(TargetFramework, Version)> CreateGeneratorFactory(StubEnvironment env) + { + IMarshallingGeneratorFactory generatorFactory; + + // If we're in a "supported" scenario, then emit a diagnostic as our final fallback. + generatorFactory = new UnsupportedMarshallingFactory(); + + generatorFactory = new NoMarshallingInfoErrorMarshallingFactory(generatorFactory); + + // The presence of System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute is tied to TFM, + // so we use TFM in the generator factory key instead of the Compilation as the compilation changes on every keystroke. + IAssemblySymbol coreLibraryAssembly = env.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; + ITypeSymbol? disabledRuntimeMarshallingAttributeType = coreLibraryAssembly.GetTypeByMetadataName(TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute); + bool runtimeMarshallingDisabled = disabledRuntimeMarshallingAttributeType is not null + && env.Compilation.Assembly.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, disabledRuntimeMarshallingAttributeType)); + + // Since the char type can go into the P/Invoke signature here, we can only use it when + // runtime marshalling is disabled. + generatorFactory = new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: runtimeMarshallingDisabled); + + InteropGenerationOptions interopGenerationOptions = new(UseMarshalType: true); + generatorFactory = new MarshalAsMarshallingGeneratorFactory(interopGenerationOptions, generatorFactory); + + IMarshallingGeneratorFactory elementFactory = new AttributedMarshallingModelGeneratorFactory( + // Since the char type in an array will not be part of the P/Invoke signature, we can + // use the regular blittable marshaller in all cases. + new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true), + new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut)); + // We don't need to include the later generator factories for collection elements + // as the later generator factories only apply to parameters. + generatorFactory = new AttributedMarshallingModelGeneratorFactory( + generatorFactory, + elementFactory, + new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut)); + + generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); + + return MarshallingGeneratorFactoryKey.Create((env.TargetFramework, env.TargetFrameworkVersion), generatorFactory); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs index 77855eaee06e4d..e2dba4aa0ae18a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs @@ -95,7 +95,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo bool mayRequireAdditionalWork = diagnostics.AnyDiagnostics; bool anyExplicitlyUnsupportedInfo = false; - var stubCodeContext = new ManagedToNativeStubCodeContext(env, "return", "nativeReturn"); + var stubCodeContext = new ManagedToNativeStubCodeContext(env.TargetFramework, env.TargetFrameworkVersion, "return", "nativeReturn"); var forwarder = new Forwarder(); // We don't actually need the bound generators. We just need them to be attempted to be bound to determine if the generator will be able to bind them. diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs index 70ada65966b061..4f4e826a2d88b4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs @@ -21,36 +21,24 @@ namespace Microsoft.Interop [Generator] public sealed class LibraryImportGenerator : IIncrementalGenerator { + internal readonly record struct ForwardedAttributes(ImmutableArray Syntax) + { + public bool Equals(ForwardedAttributes other) + { + return Syntax.SequenceEqual(other.Syntax, (IEqualityComparer)SyntaxEquivalentComparer.Instance); + } + + public override int GetHashCode() => throw new UnreachableException(); + } internal sealed record IncrementalStubGenerationContext( - StubEnvironment Environment, SignatureContext SignatureContext, ContainingSyntaxContext ContainingSyntaxContext, ContainingSyntax StubMethodSyntaxTemplate, MethodSignatureDiagnosticLocations DiagnosticLocation, - ImmutableArray ForwardedAttributes, + ForwardedAttributes ForwardedAttributes, LibraryImportData LibraryImportData, - MarshallingGeneratorFactoryKey<(TargetFramework, Version, LibraryImportGeneratorOptions)> GeneratorFactoryKey, - ImmutableArray Diagnostics) - { - public bool Equals(IncrementalStubGenerationContext? other) - { - return other is not null - && StubEnvironment.AreCompilationSettingsEqual(Environment, other.Environment) - && SignatureContext.Equals(other.SignatureContext) - && ContainingSyntaxContext.Equals(other.ContainingSyntaxContext) - && StubMethodSyntaxTemplate.Equals(other.StubMethodSyntaxTemplate) - && LibraryImportData.Equals(other.LibraryImportData) - && DiagnosticLocation.Equals(DiagnosticLocation) - && ForwardedAttributes.SequenceEqual(other.ForwardedAttributes, (IEqualityComparer)SyntaxEquivalentComparer.Instance) - && GeneratorFactoryKey.Equals(other.GeneratorFactoryKey) - && Diagnostics.SequenceEqual(other.Diagnostics); - } - - public override int GetHashCode() - { - throw new UnreachableException(); - } - } + MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version Version, LibraryImportGeneratorOptions Options)> GeneratorFactoryKey, + ImmutableArray Diagnostics); public static class StepNames { @@ -318,12 +306,11 @@ private static IncrementalStubGenerationContext CalculateStubInformation( List additionalAttributes = GenerateSyntaxForForwardedAttributes(suppressGCTransitionAttribute, unmanagedCallConvAttribute, defaultDllImportSearchPathsAttribute); return new IncrementalStubGenerationContext( - environment, signatureContext, containingTypeContext, methodSyntaxTemplate, new MethodSignatureDiagnosticLocations(originalSyntax), - additionalAttributes.ToImmutableArray(), + new ForwardedAttributes(additionalAttributes.ToImmutableArray()), libraryImportData, LibraryImportGeneratorHelpers.CreateGeneratorFactory(environment, options), generatorDiagnostics.Diagnostics.ToImmutableArray()); @@ -341,7 +328,8 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou // Generate stub code var stubGenerator = new PInvokeStubCodeGenerator( - pinvokeStub.Environment, + pinvokeStub.GeneratorFactoryKey.Key.TargetFramework, + pinvokeStub.GeneratorFactoryKey.Key.Version, pinvokeStub.SignatureContext.ElementTypeInformation, pinvokeStub.LibraryImportData.SetLastError && !options.GenerateForwarders, (elementInfo, ex) => @@ -358,7 +346,7 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou return (PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, !stubGenerator.SupportsTargetFramework, pinvokeStub, diagnostics), pinvokeStub.Diagnostics.AddRange(diagnostics.Diagnostics)); } - ImmutableArray forwardedAttributes = pinvokeStub.ForwardedAttributes; + ImmutableArray forwardedAttributes = pinvokeStub.ForwardedAttributes.Syntax; const string innerPInvokeName = "__PInvoke"; diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj index 9077f4cf523cb6..0a331d098e3773 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj @@ -9,7 +9,7 @@ RS2008;$(NoWarn) - cs + cs diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs index 66b7c5f2f85442..71cb7e06968bdf 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/PInvokeStubCodeGenerator.cs @@ -4,9 +4,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; -using System.Linq; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; @@ -49,7 +46,8 @@ internal sealed class PInvokeStubCodeGenerator private readonly ManagedToNativeStubCodeContext _context; public PInvokeStubCodeGenerator( - StubEnvironment environment, + TargetFramework targetFramework, + Version targetFrameworkVersion, ImmutableArray argTypes, bool setLastError, Action marshallingNotSupportedCallback, @@ -61,21 +59,21 @@ public PInvokeStubCodeGenerator( // supports target framework value with this value. if (_setLastError) { - SupportsTargetFramework = environment.TargetFramework == TargetFramework.Net - && environment.TargetFrameworkVersion.Major >= 6; + SupportsTargetFramework = targetFramework == TargetFramework.Net + && targetFrameworkVersion.Major >= 6; } else { SupportsTargetFramework = true; } - _context = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnIdentifier); + _context = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier); _marshallers = new BoundGenerators(argTypes, CreateGenerator); if (_marshallers.ManagedReturnMarshaller.Generator.UsesNativeIdentifier(_marshallers.ManagedReturnMarshaller.TypeInfo, _context)) { // If we need a different native return identifier, then recreate the context with the correct identifier before we generate any code. - _context = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, $"{ReturnIdentifier}{StubCodeContext.GeneratedNativeIdentifierSuffix}"); + _context = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, $"{ReturnIdentifier}{StubCodeContext.GeneratedNativeIdentifierSuffix}"); } bool noMarshallingNeeded = true; @@ -84,7 +82,7 @@ public PInvokeStubCodeGenerator( { // Check if marshalling info and generator support the current target framework. SupportsTargetFramework &= generator.TypeInfo.MarshallingAttributeInfo is not MissingSupportMarshallingInfo - && generator.Generator.IsSupported(environment.TargetFramework, environment.TargetFrameworkVersion); + && generator.Generator.IsSupported(targetFramework, targetFrameworkVersion); // Check if generator is either blittable or just a forwarder. noMarshallingNeeded &= generator is { Generator: BlittableMarshaller, TypeInfo.IsByRef: false } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedToNativeStubCodeContext.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedToNativeStubCodeContext.cs index 36b59f4600eac9..c953e246a55e26 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedToNativeStubCodeContext.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedToNativeStubCodeContext.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Text; - namespace Microsoft.Interop { public sealed record ManagedToNativeStubCodeContext : StubCodeContext @@ -22,12 +19,13 @@ public sealed record ManagedToNativeStubCodeContext : StubCodeContext private readonly string _nativeReturnIdentifier; public ManagedToNativeStubCodeContext( - StubEnvironment environment, + TargetFramework targetFramework, + Version targetFrameworkVersion, string returnIdentifier, string nativeReturnIdentifier) { - _framework = environment.TargetFramework; - _frameworkVersion = environment.TargetFrameworkVersion; + _framework = targetFramework; + _frameworkVersion = targetFrameworkVersion; _returnIdentifier = returnIdentifier; _nativeReturnIdentifier = nativeReturnIdentifier; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubEnvironment.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubEnvironment.cs index 268749de6dd6af..769c391b238b48 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubEnvironment.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubEnvironment.cs @@ -2,18 +2,8 @@ // 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.Reflection; -using System.Runtime.InteropServices; -using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Microsoft.Interop { @@ -21,21 +11,5 @@ public sealed record StubEnvironment( Compilation Compilation, TargetFramework TargetFramework, Version TargetFrameworkVersion, - bool ModuleSkipLocalsInit) - { - /// - /// Override for determining if two StubEnvironment instances are - /// equal. This intentionally excludes the Compilation instance - /// since that represents the actual compilation and not just the settings. - /// - /// The first StubEnvironment - /// The second StubEnvironment - /// True if the settings are equal, otherwise false. - public static bool AreCompilationSettingsEqual(StubEnvironment env1, StubEnvironment env2) - { - return env1.TargetFramework == env2.TargetFramework - && env1.TargetFrameworkVersion == env2.TargetFrameworkVersion - && env1.ModuleSkipLocalsInit == env2.ModuleSkipLocalsInit; - } - } + bool ModuleSkipLocalsInit); } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs index 204864133c55a4..1da2b396ef880a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs @@ -210,5 +210,52 @@ public async Task ChangingMarshallingAttributes_SameStrategy_DoesNotRegenerate() output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason)); }); } + + [Fact] + public async Task GeneratorRun_WithNewCompilation_DoesNotKeepOldCompilationAlive() + { + string source = $"namespace NS{{{CodeSnippets.BasicParametersAndModifiers()}}}"; + + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)); + + Compilation comp1 = await TestUtils.CreateCompilation(new[] { syntaxTree }); + + var (reference, driver) = RunTwoGeneratorOnTwoIterativeCompilationsAndReturnFirst(comp1); + + GC.Collect(); + + Assert.False(reference.IsAlive); + GC.KeepAlive(driver); + + static (WeakReference reference, GeneratorDriver driver) RunTwoGeneratorOnTwoIterativeCompilationsAndReturnFirst(Compilation startingCompilation) + { + Compilation comp2 = startingCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct NewType {}", new CSharpParseOptions(LanguageVersion.Preview))); + + Microsoft.Interop.LibraryImportGenerator generator = new(); + GeneratorDriver driver = TestUtils.CreateDriver(comp2, null, new[] { generator }, EnableIncrementalTrackingDriverOptions); + + driver = driver.RunGenerators(comp2); + + Compilation comp3 = comp2.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct NewType2 {}", new CSharpParseOptions(LanguageVersion.Preview))); + + GeneratorDriver driver2 = driver.RunGenerators(comp3); + + // Assert here that we did use the last result and didn't regenerate. + Assert.Collection(driver2.GetRunResult().Results, + result => + { + Assert.Collection(result.TrackedSteps[StepNames.CalculateStubInformation], + step => + { + Assert.Collection(step.Outputs, + output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason)); + }); + }); + + // Return a weak reference to the first edited compilation and the driver from the most recent run. + // The most recent run with comp3 shouldn't keep anything from comp2 alive. + return (new WeakReference(comp2), driver2); + } + } } } From d01947dc343a097cb1441296da564238cacd756e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 29 Sep 2022 14:46:26 -0700 Subject: [PATCH 2/4] Use a wrapper struct to make using elementwise equality for immutable arrays easier. --- .../JSImportGenerator/JSExportGenerator.cs | 6 ++--- .../JSImportGenerator/JSImportGenerator.cs | 6 ++--- .../LibraryImportGenerator.cs | 26 +++++++------------ .../SequenceEqualImmutableArray.cs | 25 ++++++++++++++++++ .../SyntaxEquivalentComparer.cs | 4 --- .../IncrementalGenerationTests.cs | 5 ++-- 6 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index d84440e0750870..ab4c93dc48cd27 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -23,7 +23,7 @@ internal sealed record IncrementalStubGenerationContext( MethodSignatureDiagnosticLocations DiagnosticLocation, JSExportData JSExportData, MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion, JSGeneratorOptions)> GeneratorFactoryKey, - ImmutableArray Diagnostics); + SequenceEqualImmutableArray Diagnostics); public static class StepNames { @@ -200,7 +200,7 @@ private static IncrementalStubGenerationContext CalculateStubInformation( new MethodSignatureDiagnosticLocations(originalSyntax), jsExportData, CreateGeneratorFactory(environment, options), - generatorDiagnostics.Diagnostics.ToImmutableArray()); + new SequenceEqualImmutableArray(generatorDiagnostics.Diagnostics.ToImmutableArray())); } private static MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> CreateGeneratorFactory(StubEnvironment env, JSGeneratorOptions options) @@ -230,7 +230,7 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou BlockSyntax wrapper = stubGenerator.GenerateJSExportBody(); BlockSyntax registration = stubGenerator.GenerateJSExportRegistration(); - return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, wrapper, registration), incrementalContext.Diagnostics.AddRange(diagnostics.Diagnostics)); + return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, wrapper, registration), incrementalContext.Diagnostics.Array.AddRange(diagnostics.Diagnostics)); } private static bool ShouldVisitNode(SyntaxNode syntaxNode) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs index 6aed61fe5dc117..4a387419f8128a 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs @@ -25,7 +25,7 @@ internal sealed record IncrementalStubGenerationContext( MethodSignatureDiagnosticLocations DiagnosticLocation, JSImportData JSImportData, MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion, JSGeneratorOptions)> GeneratorFactoryKey, - ImmutableArray Diagnostics); + SequenceEqualImmutableArray Diagnostics); public static class StepNames { @@ -211,7 +211,7 @@ private static IncrementalStubGenerationContext CalculateStubInformation( new MethodSignatureDiagnosticLocations(originalSyntax), jsImportData, CreateGeneratorFactory(environment, options), - generatorDiagnostics.Diagnostics.ToImmutableArray()); + new SequenceEqualImmutableArray(generatorDiagnostics.Diagnostics.ToImmutableArray())); } private static MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> CreateGeneratorFactory(StubEnvironment env, JSGeneratorOptions options) @@ -242,7 +242,7 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou BlockSyntax code = stubGenerator.GenerateJSImportBody(); - return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, code), incrementalContext.Diagnostics.AddRange(diagnostics.Diagnostics)); + return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, code), incrementalContext.Diagnostics.Array.AddRange(diagnostics.Diagnostics)); } private static bool ShouldVisitNode(SyntaxNode syntaxNode) diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs index 4f4e826a2d88b4..88aaa11d820517 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs @@ -21,24 +21,15 @@ namespace Microsoft.Interop [Generator] public sealed class LibraryImportGenerator : IIncrementalGenerator { - internal readonly record struct ForwardedAttributes(ImmutableArray Syntax) - { - public bool Equals(ForwardedAttributes other) - { - return Syntax.SequenceEqual(other.Syntax, (IEqualityComparer)SyntaxEquivalentComparer.Instance); - } - - public override int GetHashCode() => throw new UnreachableException(); - } internal sealed record IncrementalStubGenerationContext( SignatureContext SignatureContext, ContainingSyntaxContext ContainingSyntaxContext, ContainingSyntax StubMethodSyntaxTemplate, MethodSignatureDiagnosticLocations DiagnosticLocation, - ForwardedAttributes ForwardedAttributes, + SequenceEqualImmutableArray ForwardedAttributes, LibraryImportData LibraryImportData, MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version Version, LibraryImportGeneratorOptions Options)> GeneratorFactoryKey, - ImmutableArray Diagnostics); + SequenceEqualImmutableArray Diagnostics); public static class StepNames { @@ -310,10 +301,11 @@ private static IncrementalStubGenerationContext CalculateStubInformation( containingTypeContext, methodSyntaxTemplate, new MethodSignatureDiagnosticLocations(originalSyntax), - new ForwardedAttributes(additionalAttributes.ToImmutableArray()), + new SequenceEqualImmutableArray(additionalAttributes.ToImmutableArray(), SyntaxEquivalentComparer.Instance), libraryImportData, LibraryImportGeneratorHelpers.CreateGeneratorFactory(environment, options), - generatorDiagnostics.Diagnostics.ToImmutableArray()); + new SequenceEqualImmutableArray(generatorDiagnostics.Diagnostics.ToImmutableArray()) + ); } private static (MemberDeclarationSyntax, ImmutableArray) GenerateSource( @@ -323,7 +315,7 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou var diagnostics = new GeneratorDiagnostics(); if (options.GenerateForwarders) { - return (PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, explicitForwarding: true, pinvokeStub, diagnostics), pinvokeStub.Diagnostics.AddRange(diagnostics.Diagnostics)); + return (PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, explicitForwarding: true, pinvokeStub, diagnostics), pinvokeStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics)); } // Generate stub code @@ -343,10 +335,10 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou if (stubGenerator.StubIsBasicForwarder || !stubGenerator.SupportsTargetFramework) { - return (PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, !stubGenerator.SupportsTargetFramework, pinvokeStub, diagnostics), pinvokeStub.Diagnostics.AddRange(diagnostics.Diagnostics)); + return (PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, !stubGenerator.SupportsTargetFramework, pinvokeStub, diagnostics), pinvokeStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics)); } - ImmutableArray forwardedAttributes = pinvokeStub.ForwardedAttributes.Syntax; + ImmutableArray forwardedAttributes = pinvokeStub.ForwardedAttributes.Array; const string innerPInvokeName = "__PInvoke"; @@ -367,7 +359,7 @@ private static (MemberDeclarationSyntax, ImmutableArray) GenerateSou dllImport = dllImport.WithLeadingTrivia(Comment("// Local P/Invoke")); code = code.AddStatements(dllImport); - return (pinvokeStub.ContainingSyntaxContext.WrapMemberInContainingSyntaxWithUnsafeModifier(PrintGeneratedSource(pinvokeStub.StubMethodSyntaxTemplate, pinvokeStub.SignatureContext, code)), pinvokeStub.Diagnostics.AddRange(diagnostics.Diagnostics)); + return (pinvokeStub.ContainingSyntaxContext.WrapMemberInContainingSyntaxWithUnsafeModifier(PrintGeneratedSource(pinvokeStub.StubMethodSyntaxTemplate, pinvokeStub.SignatureContext, code)), pinvokeStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics)); } private static MemberDeclarationSyntax PrintForwarderStub(ContainingSyntax userDeclaredMethod, bool explicitForwarding, IncrementalStubGenerationContext stub, GeneratorDiagnostics diagnostics) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs new file mode 100644 index 00000000000000..20d81168d77a68 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs @@ -0,0 +1,25 @@ +// 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; + +namespace Microsoft.Interop +{ + public readonly record struct SequenceEqualImmutableArray(ImmutableArray Array, IEqualityComparer Comparer) + { + public SequenceEqualImmutableArray(ImmutableArray array) + : this(array, EqualityComparer.Default) + { + } + + public bool Equals(SequenceEqualImmutableArray other) + { + return Array.SequenceEqual(other.Array, Comparer); + } + + public override int GetHashCode() => throw new UnreachableException(); + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SyntaxEquivalentComparer.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SyntaxEquivalentComparer.cs index e56165393330d1..31887788c314c4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SyntaxEquivalentComparer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SyntaxEquivalentComparer.cs @@ -1,9 +1,7 @@ // 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.Text; using Microsoft.CodeAnalysis; namespace Microsoft.Interop @@ -12,8 +10,6 @@ public sealed class SyntaxEquivalentComparer : IEqualityComparer, IE { public static readonly SyntaxEquivalentComparer Instance = new(); - private SyntaxEquivalentComparer() { } - public bool Equals(SyntaxNode x, SyntaxNode y) { if ((x is null) != (y is null)) diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs index 1da2b396ef880a..47605e7875a459 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs @@ -66,11 +66,10 @@ public async Task AppendingUnrelatedSource_DoesNotRegenerateSource() GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; - Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation], + Assert.Collection(runResult.TrackedSteps[StepNames.GenerateSingleStub], step => { - // The input contains symbols and Compilation objects, so it will always be different. - // However, we validate that the calculated stub information is identical. + // The calculated stub information will differ since we have a new syntax tree for where to report diagnostics. Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason)); }); From ea2f98c861e627e7e1e63b15f76de0a78dcae658 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 30 Sep 2022 17:26:34 -0700 Subject: [PATCH 3/4] Remove accidentally included file --- .../ComInterfaceGeneratorHelpers.cs | 54 ------------------- 1 file changed, 54 deletions(-) delete mode 100644 src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs deleted file mode 100644 index f9f0bf684ff821..00000000000000 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs +++ /dev/null @@ -1,54 +0,0 @@ -// 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.Linq; -using System.Text; -using Microsoft.CodeAnalysis; - -namespace Microsoft.Interop -{ - internal static class ComInterfaceGeneratorHelpers - { - public static MarshallingGeneratorFactoryKey<(TargetFramework, Version)> CreateGeneratorFactory(StubEnvironment env) - { - IMarshallingGeneratorFactory generatorFactory; - - // If we're in a "supported" scenario, then emit a diagnostic as our final fallback. - generatorFactory = new UnsupportedMarshallingFactory(); - - generatorFactory = new NoMarshallingInfoErrorMarshallingFactory(generatorFactory); - - // The presence of System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute is tied to TFM, - // so we use TFM in the generator factory key instead of the Compilation as the compilation changes on every keystroke. - IAssemblySymbol coreLibraryAssembly = env.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; - ITypeSymbol? disabledRuntimeMarshallingAttributeType = coreLibraryAssembly.GetTypeByMetadataName(TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute); - bool runtimeMarshallingDisabled = disabledRuntimeMarshallingAttributeType is not null - && env.Compilation.Assembly.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, disabledRuntimeMarshallingAttributeType)); - - // Since the char type can go into the P/Invoke signature here, we can only use it when - // runtime marshalling is disabled. - generatorFactory = new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: runtimeMarshallingDisabled); - - InteropGenerationOptions interopGenerationOptions = new(UseMarshalType: true); - generatorFactory = new MarshalAsMarshallingGeneratorFactory(interopGenerationOptions, generatorFactory); - - IMarshallingGeneratorFactory elementFactory = new AttributedMarshallingModelGeneratorFactory( - // Since the char type in an array will not be part of the P/Invoke signature, we can - // use the regular blittable marshaller in all cases. - new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true), - new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut)); - // We don't need to include the later generator factories for collection elements - // as the later generator factories only apply to parameters. - generatorFactory = new AttributedMarshallingModelGeneratorFactory( - generatorFactory, - elementFactory, - new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut)); - - generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); - - return MarshallingGeneratorFactoryKey.Create((env.TargetFramework, env.TargetFrameworkVersion), generatorFactory); - } - } -} From 2479ec9f7223e7ad273cacca8303061b0552910e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 30 Sep 2022 21:13:17 -0700 Subject: [PATCH 4/4] PR feedback --- .../SequenceEqualImmutableArray.cs | 6 ++++++ .../IncrementalGenerationTests.cs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs index 20d81168d77a68..f91d7be4ea2bcb 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/SequenceEqualImmutableArray.cs @@ -8,6 +8,12 @@ namespace Microsoft.Interop { + /// + /// This method provides a wrapper for an that overrides the equality operation to provide elementwise comparison. + /// The default equality operation for an is reference equality of the underlying array, which is too strict + /// for many scenarios. This wrapper type allows us to use s in our other record types without having to write an Equals method + /// that we may forget to update if we add new elements to the record. + /// public readonly record struct SequenceEqualImmutableArray(ImmutableArray Array, IEqualityComparer Comparer) { public SequenceEqualImmutableArray(ImmutableArray array) diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs index 47605e7875a459..215ee20ece1596 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; @@ -226,6 +227,7 @@ public async Task GeneratorRun_WithNewCompilation_DoesNotKeepOldCompilationAlive Assert.False(reference.IsAlive); GC.KeepAlive(driver); + [MethodImpl(MethodImplOptions.NoInlining)] static (WeakReference reference, GeneratorDriver driver) RunTwoGeneratorOnTwoIterativeCompilationsAndReturnFirst(Compilation startingCompilation) { Compilation comp2 = startingCompilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText("struct NewType {}", new CSharpParseOptions(LanguageVersion.Preview)));