diff --git a/src/libraries/Common/tests/SourceGenerators/GlobalOptionsOnlyProvider.cs b/src/libraries/Common/tests/SourceGenerators/GlobalOptionsOnlyProvider.cs new file mode 100644 index 0000000000000..09b8b86af77d0 --- /dev/null +++ b/src/libraries/Common/tests/SourceGenerators/GlobalOptionsOnlyProvider.cs @@ -0,0 +1,50 @@ +// 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.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.Interop; +using Microsoft.Interop.UnitTests; +using SourceGenerators.Tests; + +namespace SourceGenerators.Tests +{ + /// + /// An implementation of that provides configuration in code + /// of global options. + /// + internal class GlobalOptionsOnlyProvider : AnalyzerConfigOptionsProvider + { + public GlobalOptionsOnlyProvider(AnalyzerConfigOptions globalOptions) + { + GlobalOptions = globalOptions; + } + + public sealed override AnalyzerConfigOptions GlobalOptions { get; } + + public sealed override AnalyzerConfigOptions GetOptions(SyntaxTree tree) + { + return EmptyOptions.Instance; + } + + public sealed override AnalyzerConfigOptions GetOptions(AdditionalText textFile) + { + return EmptyOptions.Instance; + } + + private sealed class EmptyOptions : AnalyzerConfigOptions + { + public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) + { + value = null; + return false; + } + + public static AnalyzerConfigOptions Instance = new EmptyOptions(); + } + } +} 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 0a47ad0a00891..69bd46cbf5cec 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/ConvertToLibraryImportAnalyzer.cs @@ -55,11 +55,19 @@ public override void Initialize(AnalysisContext context) if (libraryImportAttrType == null) return; - context.RegisterSymbolAction(symbolContext => AnalyzeSymbol(symbolContext, libraryImportAttrType), SymbolKind.Method); + TargetFrameworkSettings targetFramework = context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.GetTargetFrameworkSettings(); + + StubEnvironment env = new StubEnvironment( + context.Compilation, + targetFramework.TargetFramework, + targetFramework.Version, + context.Compilation.SourceModule.GetAttributes().Any(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute)); + + context.RegisterSymbolAction(symbolContext => AnalyzeSymbol(symbolContext, libraryImportAttrType, env), SymbolKind.Method); }); } - private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol libraryImportAttrType) + private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol libraryImportAttrType, StubEnvironment env) { var method = (IMethodSymbol)context.Symbol; @@ -86,7 +94,6 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo // If any diagnostics or failures to marshal are reported, then mark this diagnostic with a property signifying that it may require // later user work. AnyDiagnosticsSink diagnostics = new(); - StubEnvironment env = context.Compilation.CreateStubEnvironment(); AttributeData dllImportAttribute = method.GetAttributes().First(attr => attr.AttributeClass.ToDisplayString() == TypeNames.DllImportAttribute); SignatureContext targetSignatureContext = SignatureContext.Create(method, DefaultMarshallingInfoParser.Create(env, diagnostics, method, CreateInteropAttributeDataFromDllImport(dllImportData), dllImportAttribute), env, typeof(ConvertToLibraryImportAnalyzer).Assembly); diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator.props b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator.props index 14caceaf8e4d2..f4f1372459d20 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator.props +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator.props @@ -15,5 +15,9 @@ of generating a stub that handles all of the marshalling. --> + + + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/AnalyzerConfigOptionsExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/AnalyzerConfigOptionsExtensions.cs new file mode 100644 index 0000000000000..c7cfc69972d33 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/AnalyzerConfigOptionsExtensions.cs @@ -0,0 +1,57 @@ +// 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.Reflection; +using System.Text; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.Interop +{ + // This type is a record to get the generated equality and hashing operators + // which will be faster than the reflection-based ones. + public readonly record struct TargetFrameworkSettings(TargetFramework TargetFramework, Version Version); + + public static class AnalyzerConfigOptionsExtensions + { + private static readonly Version FirstNonCoreVersion = new(5, 0); + + // Parse from the informational version as that is the only version that always matches the TFM version + // even in debug builds. + private static readonly Version ThisAssemblyVersion = Version.Parse( + typeof(IncrementalGeneratorInitializationContextExtensions).Assembly + .GetCustomAttribute().InformationalVersion.Split('-')[0]); + + public static TargetFrameworkSettings GetTargetFrameworkSettings(this AnalyzerConfigOptions options) + { + // Our generator only runs in the following scenarios: + // - In the dotnet/runtime repository. + // - In a .NET SDK for the same TFM that matches the version of this assembly. + // We'll try to pull the TFM information from the build, but if it is not present, + // then we'll assume we're in the ref pack as the TFM information will always be present in the dotnet/runtime build. + options.TryGetValue("build_property.TargetFrameworkIdentifier", out string? frameworkIdentifier); + options.TryGetValue("build_property.TargetFrameworkVersion", out string? versionString); + // TargetFrameworkVersion starts with a 'v'. + Version? version = versionString is not null ? Version.Parse(versionString.Substring(1)) : null; + return new TargetFrameworkSettings( + frameworkIdentifier switch + { + ".NETStandard" => TargetFramework.Standard, + ".NETCoreApp" when version is not null && version < FirstNonCoreVersion => TargetFramework.Core, + ".NETCoreApp" => TargetFramework.Net, + // If the TFM is not specified, we'll infer it from this assembly. + // Since we only ship this assembly as part of the Microsoft.NETCore.App TFM, + // the down-level support only matters for the repo where this project is built. + // In all other cases, we will only be used from the TFM with the matching version as our assembly. + null => TargetFramework.Net, + // Assume that all unknown target framework identifiers are .NET Framework. + // All legacy target frameworks will have effectively the same feature set as we provide for .NET Framework + // for our purposes. + _ => TargetFramework.Framework + }, + // If the version is not specified, we'll infer it from this assembly. + version ?? ThisAssemblyVersion); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CompilationExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CompilationExtensions.cs deleted file mode 100644 index 570db386c5e98..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CompilationExtensions.cs +++ /dev/null @@ -1,42 +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 -{ - public static class CompilationExtensions - { - public static StubEnvironment CreateStubEnvironment(this Compilation compilation) - { - TargetFramework targetFramework = DetermineTargetFramework(compilation, out Version targetFrameworkVersion); - return new StubEnvironment( - compilation, - targetFramework, - targetFrameworkVersion, - compilation.SourceModule.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute)); - - static TargetFramework DetermineTargetFramework(Compilation compilation, out Version version) - { - IAssemblySymbol systemAssembly = compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; - version = systemAssembly.Identity.Version; - - return systemAssembly.Identity.Name switch - { - // .NET Framework - "mscorlib" => TargetFramework.Framework, - // .NET Standard - "netstandard" => TargetFramework.Standard, - // .NET Core (when version < 5.0) or .NET - "System.Runtime" or "System.Private.CoreLib" => - (version.Major < 5) ? TargetFramework.Core : TargetFramework.Net, - _ => TargetFramework.Unknown, - }; - } - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs index b4a20afc3e712..069daeb130fff 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalGeneratorInitializationContextExtensions.cs @@ -5,8 +5,10 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Reflection; using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.Interop { @@ -14,7 +16,25 @@ public static class IncrementalGeneratorInitializationContextExtensions { public static IncrementalValueProvider CreateStubEnvironmentProvider(this IncrementalGeneratorInitializationContext context) { - return context.CompilationProvider.Select(static (comp, ct) => comp.CreateStubEnvironment()); + var tfmVersion = context.AnalyzerConfigOptionsProvider + .Select((options, ct) => options.GlobalOptions.GetTargetFrameworkSettings()); + + var isModuleSkipLocalsInit = context.SyntaxProvider + .ForAttributeWithMetadataName( + TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute, + (node, ct) => node is ICompilationUnitSyntax, + // If SkipLocalsInit is applied at the top level, it is either applied to the module + // or is invalid syntax. As a result, we just need to know if there's any top-level + // SkipLocalsInit attributes. So the result we return here is meaningless. + (context, ct) => true) + .Collect() + .Select((topLevelAttrs, ct) => !topLevelAttrs.IsEmpty); + + return tfmVersion + .Combine(isModuleSkipLocalsInit) + .Combine(context.CompilationProvider) + .Select((data, ct) => + new StubEnvironment(data.Right, data.Left.Left.TargetFramework, data.Left.Left.Version, data.Left.Right)); } public static void RegisterDiagnostics(this IncrementalGeneratorInitializationContext context, IncrementalValuesProvider diagnostics) diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj index 24f484a369624..64e7dd10a070d 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj @@ -10,9 +10,13 @@ + Link="Common\SourceGenerators\LiveReferencePack.cs" /> + + + /// An implementation of that provides configuration in code + /// of the target framework options. Used when testing interop source generators. + /// + public class TargetFrameworkConfigOptions : AnalyzerConfigOptions + { + private static readonly string _liveTargetFrameworkVersion; + private readonly string _targetFrameworkIdentifier; + private readonly string _targetFrameworkVersion; + + static TargetFrameworkConfigOptions() + { + Version liveVersion = Version.Parse( + typeof(TargetFrameworkConfigOptions) + .Assembly.GetCustomAttribute()! + .InformationalVersion.Split('-')[0]); + _liveTargetFrameworkVersion = $"v{liveVersion.ToString(2)}"; + } + + public TargetFrameworkConfigOptions(TestTargetFramework targetFramework) + { + _targetFrameworkIdentifier = targetFramework switch + { + TestTargetFramework.Framework => ".NETFramework", + TestTargetFramework.Standard => ".NETStandard", + _ => ".NETCoreApp" + }; + _targetFrameworkVersion = targetFramework switch + { + TestTargetFramework.Framework => "v4.8", + TestTargetFramework.Standard => "v2.1", + TestTargetFramework.Core => "v3.1", + TestTargetFramework.Net6 => "v6.0", + TestTargetFramework.Net => _liveTargetFrameworkVersion, + _ => throw new UnreachableException() + }; + } + + public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) + { + switch (key) + { + case "build_property.TargetFrameworkIdentifier": + value = _targetFrameworkIdentifier; + return true; + + case "build_property.TargetFrameworkVersion": + value = _targetFrameworkVersion; + return true; + + default: + value = null; + return false; + } + } + } + +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs index 4d7f94678e69a..81543e8b3d5d8 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; using Microsoft.DotNet.XUnitExtensions; +using SourceGenerators.Tests; using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs index 2e3604b07a6e9..7d18c9f9fabe0 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop.UnitTests; +using SourceGenerators.Tests; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; @@ -155,7 +156,7 @@ partial class C }}"; Compilation comp = await TestUtils.CreateCompilation(source, targetFramework); - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); + Compilation newComp = TestUtils.RunGenerators(comp, new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(targetFramework)), out _, new Microsoft.Interop.LibraryImportGenerator()); ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs index 5ef6845108e68..ea0a8986d33c5 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs @@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Interop; using Microsoft.Interop.UnitTests; +using SourceGenerators.Tests; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -350,7 +351,11 @@ partial class C } " + CodeSnippets.LibraryImportAttributeDeclaration; Compilation origComp = await TestUtils.CreateCompilation(source, TestTargetFramework.Standard); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); + Compilation newComp = TestUtils.RunGenerators( + origComp, + new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(TestTargetFramework.Standard)), + out _, + new Microsoft.Interop.LibraryImportGenerator()); IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); @@ -388,7 +393,11 @@ partial class C } " + CodeSnippets.LibraryImportAttributeDeclaration; Compilation origComp = await TestUtils.CreateCompilation(source, TestTargetFramework.Standard); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); + Compilation newComp = TestUtils.RunGenerators( + origComp, + new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(TestTargetFramework.Standard)), + out _, + new Microsoft.Interop.LibraryImportGenerator()); IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs index ca2e733ea69f9..668cc60340b7b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -12,6 +12,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Xunit; +using SourceGenerators.Tests; namespace LibraryImportGenerator.UnitTests { @@ -501,6 +502,7 @@ public async Task ValidateSnippetsFallbackForwarder(string id, string source, Te var newComp = TestUtils.RunGenerators( comp, + new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(targetFramework)), out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); @@ -611,7 +613,7 @@ public async Task ValidateSnippetsWithMarshalType(string id, string source) var newComp = TestUtils.RunGenerators( comp, - new LibraryImportGeneratorOptionsProvider(useMarshalType: true, generateForwarders: false), + new LibraryImportGeneratorOptionsProvider(TestTargetFramework.Net, useMarshalType: true, generateForwarders: false), out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); @@ -660,7 +662,7 @@ public async Task ValidateNoGeneratedOuptutForNoImport(string id, string source, Compilation comp = await TestUtils.CreateCompilation(source, framework, allowUnsafe: false); TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); + var newComp = TestUtils.RunGenerators(comp, new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(framework)), out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); Assert.Empty(generatorDiags); // Assert we didn't generate any syntax trees, even empty ones diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs index 9cce7f29a42f3..1b2d9e5767752 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop; using Microsoft.Interop.UnitTests; +using SourceGenerators.Tests; using Xunit; using StringMarshalling = Microsoft.Interop.StringMarshalling; @@ -320,8 +321,11 @@ public Native(string s) { } // Compile against Standard so that we generate forwarders Compilation comp = await TestUtils.CreateCompilation(source, TestTargetFramework.Standard); TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); + Compilation newComp = TestUtils.RunGenerators( + comp, + new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(TestTargetFramework.Standard)), + out var generatorDiags, + new Microsoft.Interop.LibraryImportGenerator()); DiagnosticResult[] expectedDiags = new DiagnosticResult[] { (new DiagnosticResult(GeneratorDiagnostics.CannotForwardToDllImport)) diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj index af79b40f82074..d3c7c3c2f5479 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/LibraryImportGenerator.Unit.Tests.csproj @@ -8,9 +8,13 @@ + Link="Common\SourceGenerators\LiveReferencePack.cs" /> + + that provides configuration in code /// of the options supported by the LibraryImportGenerator source generator. Used for testing various configurations. /// - internal class LibraryImportGeneratorOptionsProvider : AnalyzerConfigOptionsProvider + internal sealed class LibraryImportGeneratorOptionsProvider : GlobalOptionsOnlyProvider { - public LibraryImportGeneratorOptionsProvider(bool useMarshalType, bool generateForwarders) + public LibraryImportGeneratorOptionsProvider(TestTargetFramework targetFramework, bool useMarshalType, bool generateForwarders) + :base(new GlobalGeneratorOptions(targetFramework, useMarshalType, generateForwarders)) { - GlobalOptions = new GlobalGeneratorOptions(useMarshalType, generateForwarders); } - public override AnalyzerConfigOptions GlobalOptions { get; } - - public override AnalyzerConfigOptions GetOptions(SyntaxTree tree) - { - return EmptyOptions.Instance; - } - - public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) - { - return EmptyOptions.Instance; - } - - private class GlobalGeneratorOptions : AnalyzerConfigOptions + private sealed class GlobalGeneratorOptions : TargetFrameworkConfigOptions { private readonly bool _useMarshalType = false; private readonly bool _generateForwarders = false; - public GlobalGeneratorOptions(bool useMarshalType, bool generateForwarders) + public GlobalGeneratorOptions(TestTargetFramework targetFramework, bool useMarshalType, bool generateForwarders) + : base(targetFramework) { _useMarshalType = useMarshalType; _generateForwarders = generateForwarders; @@ -55,21 +45,9 @@ public override bool TryGetValue(string key, [NotNullWhen(true)] out string? val return true; default: - value = null; - return false; + return base.TryGetValue(key, out value); } } } - - private class EmptyOptions : AnalyzerConfigOptions - { - public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) - { - value = null; - return false; - } - - public static AnalyzerConfigOptions Instance = new EmptyOptions(); - } } }