diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VirtualMethodIndexData.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VirtualMethodIndexData.cs
index 62caf56448648..c5a7b93f492ed 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VirtualMethodIndexData.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VirtualMethodIndexData.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Interop
///
/// VirtualMethodIndexAttribute data
///
- internal sealed record VirtualMethodIndexData(int Index) : InteropAttributeData
+ internal sealed record VirtualMethodIndexData(int Index) : InteropAttributeCompilationData
{
public bool ImplicitThisParameter { get; init; }
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/DefaultMarshallingInfoParser.cs b/src/libraries/System.Runtime.InteropServices/gen/Common/DefaultMarshallingInfoParser.cs
index d07cfd88010ae..2150eacf9689c 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Common/DefaultMarshallingInfoParser.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Common/DefaultMarshallingInfoParser.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Interop
{
internal static class DefaultMarshallingInfoParser
{
- public static MarshallingInfoParser Create(StubEnvironment env, IGeneratorDiagnostics diagnostics, IMethodSymbol method, InteropAttributeData interopAttributeData, AttributeData unparsedAttributeData)
+ public static MarshallingInfoParser Create(StubEnvironment env, IGeneratorDiagnostics diagnostics, IMethodSymbol method, InteropAttributeCompilationData interopAttributeData, AttributeData unparsedAttributeData)
{
// Compute the current default string encoding value.
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 0f1ca4252cfeb..0a47ad0a00891 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs
@@ -146,9 +146,9 @@ private static bool HasUnsupportedMarshalAsInfo(TypePositionInfo info)
|| unmanagedType == UnmanagedType.SafeArray;
}
- private static InteropAttributeData CreateInteropAttributeDataFromDllImport(DllImportData dllImportData)
+ private static InteropAttributeCompilationData CreateInteropAttributeDataFromDllImport(DllImportData dllImportData)
{
- InteropAttributeData interopData = new();
+ InteropAttributeCompilationData interopData = new();
if (dllImportData.SetLastError)
{
interopData = interopData with { IsUserDefined = interopData.IsUserDefined | InteropAttributeMember.SetLastError, SetLastError = true };
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportData.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportData.cs
index 957d3ce381a12..65691faf8beb3 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportData.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportData.cs
@@ -1,16 +1,31 @@
// 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.Runtime.InteropServices;
-using Microsoft.CodeAnalysis;
-
namespace Microsoft.Interop
{
///
- /// LibraryImportAttribute data
+ /// Contains the data related to a LibraryImportAttribute, without references to Roslyn symbols.
+ /// See for a type with a reference to the StringMarshallingCustomType
///
internal sealed record LibraryImportData(string ModuleName) : InteropAttributeData
+ {
+ public string EntryPoint { get; init; }
+
+ public static LibraryImportData From(LibraryImportCompilationData libraryImport)
+ => new LibraryImportData(libraryImport.ModuleName) with
+ {
+ EntryPoint = libraryImport.EntryPoint,
+ IsUserDefined = libraryImport.IsUserDefined,
+ SetLastError = libraryImport.SetLastError,
+ StringMarshalling = libraryImport.StringMarshalling
+ };
+ }
+
+ ///
+ /// Contains the data related to a LibraryImportAttribute, with references to Roslyn symbols.
+ /// Use instead when using for incremental compilation state to avoid keeping a compilation alive
+ ///
+ internal sealed record LibraryImportCompilationData(string ModuleName) : InteropAttributeCompilationData
{
public string EntryPoint { get; init; }
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs
index 88aaa11d82051..459fff2cb589a 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs
@@ -7,7 +7,6 @@
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
-using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -181,7 +180,7 @@ private static MemberDeclarationSyntax PrintGeneratedSource(
.WithBody(stubCode);
}
- private static LibraryImportData? ProcessLibraryImportAttribute(AttributeData attrData)
+ private static LibraryImportCompilationData? ProcessLibraryImportAttribute(AttributeData attrData)
{
// Found the LibraryImport, but it has an error so report the error.
// This is most likely an issue with targeting an incorrect TFM.
@@ -198,7 +197,7 @@ private static MemberDeclarationSyntax PrintGeneratedSource(
ImmutableDictionary namedArguments = ImmutableDictionary.CreateRange(attrData.NamedArguments);
string? entryPoint = null;
- if (namedArguments.TryGetValue(nameof(LibraryImportData.EntryPoint), out TypedConstant entryPointValue))
+ if (namedArguments.TryGetValue(nameof(LibraryImportCompilationData.EntryPoint), out TypedConstant entryPointValue))
{
if (entryPointValue.Value is not string)
{
@@ -207,7 +206,7 @@ private static MemberDeclarationSyntax PrintGeneratedSource(
entryPoint = (string)entryPointValue.Value!;
}
- return new LibraryImportData(attrData.ConstructorArguments[0].Value!.ToString())
+ return new LibraryImportCompilationData(attrData.ConstructorArguments[0].Value!.ToString())
{
EntryPoint = entryPoint,
}.WithValuesFromNamedArguments(namedArguments);
@@ -261,9 +260,9 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
var generatorDiagnostics = new GeneratorDiagnostics();
// Process the LibraryImport attribute
- LibraryImportData libraryImportData =
+ LibraryImportCompilationData libraryImportData =
ProcessLibraryImportAttribute(generatedDllImportAttr!) ??
- new LibraryImportData("INVALID_CSHARP_SYNTAX");
+ new LibraryImportCompilationData("INVALID_CSHARP_SYNTAX");
if (libraryImportData.IsUserDefined.HasFlag(InteropAttributeMember.StringMarshalling))
{
@@ -302,7 +301,7 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
methodSyntaxTemplate,
new MethodSignatureDiagnosticLocations(originalSyntax),
new SequenceEqualImmutableArray(additionalAttributes.ToImmutableArray(), SyntaxEquivalentComparer.Instance),
- libraryImportData,
+ LibraryImportData.From(libraryImportData),
LibraryImportGeneratorHelpers.CreateGeneratorFactory(environment, options),
new SequenceEqualImmutableArray(generatorDiagnostics.Diagnostics.ToImmutableArray())
);
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/InteropAttributeData.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/InteropAttributeData.cs
index c49511de23336..ecbb18426791f 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/InteropAttributeData.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/InteropAttributeData.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Immutable;
-using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
namespace Microsoft.Interop
@@ -22,9 +21,24 @@ public enum InteropAttributeMember
}
///
- /// Common data for all source-generated-interop trigger attributes
+ /// Common data for all source-generated-interop trigger attributes.
+ /// This type and derived types should not have any reference that would keep a compilation alive.
///
public record InteropAttributeData
+ {
+ ///
+ /// Value set by the user on the original declaration.
+ ///
+ public InteropAttributeMember IsUserDefined { get; init; }
+ public bool SetLastError { get; init; }
+ public StringMarshalling StringMarshalling { get; init; }
+ }
+
+ ///
+ /// Common data for all source-generated-interop trigger attributes that also includes a reference to the Roslyn symbol for StringMarshallingCustomType.
+ /// See for a type that doesn't keep a compilation alive.
+ ///
+ public record InteropAttributeCompilationData
{
///
/// Value set by the user on the original declaration.
@@ -37,14 +51,14 @@ public record InteropAttributeData
public static class InteropAttributeDataExtensions
{
- public static T WithValuesFromNamedArguments(this T t, ImmutableDictionary namedArguments) where T : InteropAttributeData
+ public static T WithValuesFromNamedArguments(this T t, ImmutableDictionary namedArguments) where T : InteropAttributeCompilationData
{
InteropAttributeMember userDefinedValues = InteropAttributeMember.None;
bool setLastError = false;
StringMarshalling stringMarshalling = StringMarshalling.Custom;
INamedTypeSymbol? stringMarshallingCustomType = null;
- if (namedArguments.TryGetValue(nameof(InteropAttributeData.SetLastError), out TypedConstant setLastErrorValue))
+ if (namedArguments.TryGetValue(nameof(InteropAttributeCompilationData.SetLastError), out TypedConstant setLastErrorValue))
{
userDefinedValues |= InteropAttributeMember.SetLastError;
if (setLastErrorValue.Value is not bool)
@@ -53,7 +67,7 @@ public static T WithValuesFromNamedArguments(this T t, ImmutableDictionary(this T t, ImmutableDictionary _syntax ??= SyntaxFactory.ParseTypeName(FullTypeName);
+ public virtual bool Equals(ManagedTypeInfo? other)
+ {
+ return other is not null
+ && Syntax.IsEquivalentTo(other.Syntax)
+ && FullTypeName == other.FullTypeName
+ && DiagnosticFormattedName == other.DiagnosticFormattedName;
+ }
+
+ public override int GetHashCode()
+ {
+ return FullTypeName.GetHashCode() ^ DiagnosticFormattedName.GetHashCode();
+ }
+
protected ManagedTypeInfo(ManagedTypeInfo original)
{
FullTypeName = original.FullTypeName;
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs
index 1f343d691ad5b..2e12f600d3736 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs
@@ -24,6 +24,24 @@ public readonly record struct CustomTypeMarshallerData(
public readonly record struct CustomTypeMarshallers(
ImmutableDictionary Modes)
{
+ public bool Equals(CustomTypeMarshallers other)
+ {
+ // Check for equal count, then check if any KeyValuePairs exist in one 'Modes'
+ // but not the other (i.e. set equality on the set of items in the dictionary)
+ return Modes.Count == other.Modes.Count
+ && !Modes.Except(other.Modes).Any();
+ }
+
+ public override int GetHashCode()
+ {
+ int hash = 0;
+ foreach (KeyValuePair mode in Modes)
+ {
+ hash ^= mode.Key.GetHashCode() ^ mode.Value.GetHashCode();
+ }
+ return hash;
+ }
+
public CustomTypeMarshallerData GetModeOrDefault(MarshalMode mode)
{
CustomTypeMarshallerData data;
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
index 8a919c642312c..5aba5d6133608 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs
@@ -964,7 +964,7 @@ public static partial void Method(
+ CustomCollectionMarshallingCodeSnippets.Stateless.In
+ CustomCollectionMarshallingCodeSnippets.CustomIntMarshaller;
- public static string RecursiveCountElementNameOnReturnValue => $@"
+ public static string RecursiveCountElementNameOnReturnValue => $@"
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
{DisableRuntimeMarshalling}
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 ef240d2810d7a..8b6a8d043e5b9 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs
@@ -1,17 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.Text;
-using Microsoft.Interop.UnitTests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using System.Text;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.Interop.UnitTests;
using Xunit;
using static Microsoft.Interop.LibraryImportGenerator;
@@ -217,8 +215,7 @@ public static IEnumerable