* 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.
* Use a wrapper struct to make using elementwise equality for immutable arrays easier.
* Remove accidentally included file
* PR feedback
private readonly JSSignatureContext _signatureContext;
public JSExportCodeGenerator(
- StubEnvironment environment,
+ TargetFramework targetFramework,
+ Version targetFrameworkVersion,
ImmutableArray<TypePositionInfo> argTypes,
JSExportData attributeData,
JSSignatureContext signatureContext,
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);
}
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<Diagnostic> 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,
+ SequenceEqualImmutableArray<Diagnostic> Diagnostics);
public static class StepNames
{
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);
var methodSyntaxTemplate = new ContainingSyntax(originalSyntax.Modifiers.StripTriviaFromTokens(), SyntaxKind.MethodDeclaration, originalSyntax.Identifier, originalSyntax.TypeParameterList);
return new IncrementalStubGenerationContext(
- environment,
signatureContext,
containingTypeContext,
methodSyntaxTemplate,
new MethodSignatureDiagnosticLocations(originalSyntax),
jsExportData,
CreateGeneratorFactory(environment, options),
- generatorDiagnostics.Diagnostics.ToImmutableArray());
+ new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
}
private static MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> CreateGeneratorFactory(StubEnvironment env, JSGeneratorOptions options)
}
private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) 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,
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)
private readonly JSSignatureContext _signatureContext;
public JSImportCodeGenerator(
- StubEnvironment environment,
+ TargetFramework targetFramework,
+ Version targetFrameworkVersion,
ImmutableArray<TypePositionInfo> argTypes,
JSImportData attributeData,
JSSignatureContext signatureContext,
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);
}
// 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;
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<Diagnostic> 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,
+ SequenceEqualImmutableArray<Diagnostic> Diagnostics);
public static class StepNames
{
var methodSyntaxTemplate = new ContainingSyntax(originalSyntax.Modifiers.StripTriviaFromTokens(), SyntaxKind.MethodDeclaration, originalSyntax.Identifier, originalSyntax.TypeParameterList);
return new IncrementalStubGenerationContext(
- environment,
signatureContext,
containingTypeContext,
methodSyntaxTemplate,
new MethodSignatureDiagnosticLocations(originalSyntax),
jsImportData,
CreateGeneratorFactory(environment, options),
- generatorDiagnostics.Diagnostics.ToImmutableArray());
+ new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
}
private static MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> CreateGeneratorFactory(StubEnvironment env, JSGeneratorOptions options)
// 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,
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)
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.
public sealed class LibraryImportGenerator : IIncrementalGenerator
{
internal sealed record IncrementalStubGenerationContext(
- StubEnvironment Environment,
SignatureContext SignatureContext,
ContainingSyntaxContext ContainingSyntaxContext,
ContainingSyntax StubMethodSyntaxTemplate,
MethodSignatureDiagnosticLocations DiagnosticLocation,
- ImmutableArray<AttributeSyntax> ForwardedAttributes,
+ SequenceEqualImmutableArray<AttributeSyntax> ForwardedAttributes,
LibraryImportData LibraryImportData,
- MarshallingGeneratorFactoryKey<(TargetFramework, Version, LibraryImportGeneratorOptions)> GeneratorFactoryKey,
- ImmutableArray<Diagnostic> 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<AttributeSyntax>)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,
+ SequenceEqualImmutableArray<Diagnostic> Diagnostics);
public static class StepNames
{
List<AttributeSyntax> additionalAttributes = GenerateSyntaxForForwardedAttributes(suppressGCTransitionAttribute, unmanagedCallConvAttribute, defaultDllImportSearchPathsAttribute);
return new IncrementalStubGenerationContext(
- environment,
signatureContext,
containingTypeContext,
methodSyntaxTemplate,
new MethodSignatureDiagnosticLocations(originalSyntax),
- additionalAttributes.ToImmutableArray(),
+ new SequenceEqualImmutableArray<AttributeSyntax>(additionalAttributes.ToImmutableArray(), SyntaxEquivalentComparer.Instance),
libraryImportData,
LibraryImportGeneratorHelpers.CreateGeneratorFactory(environment, options),
- generatorDiagnostics.Diagnostics.ToImmutableArray());
+ new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray())
+ );
}
private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateSource(
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
var stubGenerator = new PInvokeStubCodeGenerator(
- pinvokeStub.Environment,
+ pinvokeStub.GeneratorFactoryKey.Key.TargetFramework,
+ pinvokeStub.GeneratorFactoryKey.Key.Version,
pinvokeStub.SignatureContext.ElementTypeInformation,
pinvokeStub.LibraryImportData.SetLastError && !options.GenerateForwarders,
(elementInfo, ex) =>
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<AttributeSyntax> forwardedAttributes = pinvokeStub.ForwardedAttributes;
+ ImmutableArray<AttributeSyntax> forwardedAttributes = pinvokeStub.ForwardedAttributes.Array;
const string innerPInvokeName = "__PInvoke";
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)
<!-- Disable RS2008: Enable analyzer release tracking
Diagnostics in runtime use a different mechanism (docs/project/list-of-diagnostics.md) -->
<NoWarn>RS2008;$(NoWarn)</NoWarn>
- <AnalyzerLanguage>cs</AnalyzerLanguage>
+ <AnalyzerLanguage>cs</AnalyzerLanguage>
</PropertyGroup>
<ItemGroup>
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;
private readonly ManagedToNativeStubCodeContext _context;
public PInvokeStubCodeGenerator(
- StubEnvironment environment,
+ TargetFramework targetFramework,
+ Version targetFrameworkVersion,
ImmutableArray<TypePositionInfo> argTypes,
bool setLastError,
Action<TypePositionInfo, MarshallingNotSupportedException> marshallingNotSupportedCallback,
// 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;
{
// 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 }
// 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
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;
}
--- /dev/null
+// 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
+{
+ /// <summary>
+ /// This method provides a wrapper for an <see cref="ImmutableArray{T}" /> that overrides the equality operation to provide elementwise comparison.
+ /// The default equality operation for an <see cref="ImmutableArray{T}" /> is reference equality of the underlying array, which is too strict
+ /// for many scenarios. This wrapper type allows us to use <see cref="ImmutableArray{T}" />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.
+ /// </summary>
+ public readonly record struct SequenceEqualImmutableArray<T>(ImmutableArray<T> Array, IEqualityComparer<T> Comparer)
+ {
+ public SequenceEqualImmutableArray(ImmutableArray<T> array)
+ : this(array, EqualityComparer<T>.Default)
+ {
+ }
+
+ public bool Equals(SequenceEqualImmutableArray<T> other)
+ {
+ return Array.SequenceEqual(other.Array, Comparer);
+ }
+
+ public override int GetHashCode() => throw new UnreachableException();
+ }
+}
// 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
{
Compilation Compilation,
TargetFramework TargetFramework,
Version TargetFrameworkVersion,
- bool ModuleSkipLocalsInit)
- {
- /// <summary>
- /// 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.
- /// </summary>
- /// <param name="env1">The first StubEnvironment</param>
- /// <param name="env2">The second StubEnvironment</param>
- /// <returns>True if the settings are equal, otherwise false.</returns>
- public static bool AreCompilationSettingsEqual(StubEnvironment env1, StubEnvironment env2)
- {
- return env1.TargetFramework == env2.TargetFramework
- && env1.TargetFrameworkVersion == env2.TargetFrameworkVersion
- && env1.ModuleSkipLocalsInit == env2.ModuleSkipLocalsInit;
- }
- }
+ bool ModuleSkipLocalsInit);
}
// 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
{
public static readonly SyntaxEquivalentComparer Instance = new();
- private SyntaxEquivalentComparer() { }
-
public bool Equals(SyntaxNode x, SyntaxNode y)
{
if ((x is null) != (y is null))
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
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));
});
output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason));
});
}
+
+ [Fact]
+ public async Task GeneratorRun_WithNewCompilation_DoesNotKeepOldCompilationAlive()
+ {
+ string source = $"namespace NS{{{CodeSnippets.BasicParametersAndModifiers<int>()}}}";
+
+ 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);
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ 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);
+ }
+ }
}
}