diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/LibraryImportDiagnosticsAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/LibraryImportDiagnosticsAnalyzer.cs
new file mode 100644
index 00000000000000..0800b375fc4f20
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/LibraryImportDiagnosticsAnalyzer.cs
@@ -0,0 +1,300 @@
+// 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.Immutable;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
+using Microsoft.Interop;
+
+namespace Microsoft.Interop.Analyzers
+{
+ ///
+ /// Analyzer that reports diagnostics for LibraryImport methods.
+ /// This analyzer runs the same diagnostic logic as LibraryImportGenerator
+ /// but reports diagnostics separately from the source generator.
+ ///
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class LibraryImportDiagnosticsAnalyzer : DiagnosticAnalyzer
+ {
+ public override ImmutableArray SupportedDiagnostics { get; } =
+ ImmutableArray.Create(
+ GeneratorDiagnostics.InvalidAttributedMethodSignature,
+ GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers,
+ GeneratorDiagnostics.InvalidStringMarshallingConfiguration,
+ GeneratorDiagnostics.ParameterTypeNotSupported,
+ GeneratorDiagnostics.ReturnTypeNotSupported,
+ GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails,
+ GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails,
+ GeneratorDiagnostics.ParameterConfigurationNotSupported,
+ GeneratorDiagnostics.ReturnConfigurationNotSupported,
+ GeneratorDiagnostics.MarshalAsParameterConfigurationNotSupported,
+ GeneratorDiagnostics.MarshalAsReturnConfigurationNotSupported,
+ GeneratorDiagnostics.ConfigurationNotSupported,
+ GeneratorDiagnostics.ConfigurationValueNotSupported,
+ GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported,
+ GeneratorDiagnostics.CannotForwardToDllImport,
+ GeneratorDiagnostics.RequiresAllowUnsafeBlocks,
+ GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo,
+ GeneratorDiagnostics.UnnecessaryReturnMarshallingInfo,
+ GeneratorDiagnostics.SizeOfInCollectionMustBeDefinedAtCallOutParam,
+ GeneratorDiagnostics.SizeOfInCollectionMustBeDefinedAtCallReturnValue,
+ GeneratorDiagnostics.LibraryImportUsageDoesNotFollowBestPractices);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterCompilationStartAction(context =>
+ {
+ // Nothing to do if the LibraryImportAttribute is not in the compilation
+ INamedTypeSymbol? libraryImportAttrType = context.Compilation.GetBestTypeByMetadataName(TypeNames.LibraryImportAttribute);
+ if (libraryImportAttrType is null)
+ return;
+
+ StubEnvironment env = new StubEnvironment(
+ context.Compilation,
+ context.Compilation.GetEnvironmentFlags());
+
+ // Get generator options once per compilation
+ LibraryImportGeneratorOptions options = new(context.Options.AnalyzerConfigOptionsProvider.GlobalOptions);
+
+ // Track if we found any LibraryImport methods to report RequiresAllowUnsafeBlocks once
+ bool foundLibraryImportMethod = false;
+ bool unsafeEnabled = context.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true };
+
+ context.RegisterSymbolAction(symbolContext =>
+ {
+ if (AnalyzeMethod(symbolContext, env, libraryImportAttrType, options))
+ {
+ foundLibraryImportMethod = true;
+ }
+ }, SymbolKind.Method);
+
+ // Report RequiresAllowUnsafeBlocks once per compilation if there are LibraryImport methods and unsafe is not enabled
+ context.RegisterCompilationEndAction(endContext =>
+ {
+ if (foundLibraryImportMethod && !unsafeEnabled)
+ {
+ endContext.ReportDiagnostic(DiagnosticInfo.Create(GeneratorDiagnostics.RequiresAllowUnsafeBlocks, null).ToDiagnostic());
+ }
+ });
+ });
+ }
+
+ ///
+ /// Analyzes a method for LibraryImport diagnostics.
+ ///
+ /// True if the method has LibraryImportAttribute, false otherwise.
+ private static bool AnalyzeMethod(SymbolAnalysisContext context, StubEnvironment env, INamedTypeSymbol libraryImportAttrType, LibraryImportGeneratorOptions options)
+ {
+ IMethodSymbol method = (IMethodSymbol)context.Symbol;
+
+ // Only analyze methods with LibraryImportAttribute
+ AttributeData? libraryImportAttr = null;
+ foreach (AttributeData attr in method.GetAttributes())
+ {
+ if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, libraryImportAttrType))
+ {
+ libraryImportAttr = attr;
+ break;
+ }
+ }
+
+ if (libraryImportAttr is null)
+ return false;
+
+ // Find the method syntax
+ foreach (SyntaxReference syntaxRef in method.DeclaringSyntaxReferences)
+ {
+ if (syntaxRef.GetSyntax(context.CancellationToken) is MethodDeclarationSyntax methodSyntax)
+ {
+ AnalyzeMethodSyntax(context, methodSyntax, method, libraryImportAttr, env, options);
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ private static void AnalyzeMethodSyntax(
+ SymbolAnalysisContext context,
+ MethodDeclarationSyntax methodSyntax,
+ IMethodSymbol method,
+ AttributeData libraryImportAttr,
+ StubEnvironment env,
+ LibraryImportGeneratorOptions options)
+ {
+ // Check for invalid method signature
+ DiagnosticInfo? invalidMethodDiagnostic = GetDiagnosticIfInvalidMethodForGeneration(methodSyntax, method);
+ if (invalidMethodDiagnostic is not null)
+ {
+ context.ReportDiagnostic(invalidMethodDiagnostic.ToDiagnostic());
+ return; // Don't continue analysis if the method is invalid
+ }
+
+ // Note: RequiresAllowUnsafeBlocks is reported once per compilation in Initialize method
+
+ // Calculate stub information and collect diagnostics
+ var diagnostics = CalculateDiagnostics(methodSyntax, method, libraryImportAttr, env, options, context.CancellationToken);
+
+ foreach (DiagnosticInfo diagnostic in diagnostics)
+ {
+ context.ReportDiagnostic(diagnostic.ToDiagnostic());
+ }
+ }
+
+ private static ImmutableArray CalculateDiagnostics(
+ MethodDeclarationSyntax originalSyntax,
+ IMethodSymbol symbol,
+ AttributeData libraryImportAttr,
+ StubEnvironment environment,
+ LibraryImportGeneratorOptions options,
+ CancellationToken ct)
+ {
+ ct.ThrowIfCancellationRequested();
+
+ var locations = new MethodSignatureDiagnosticLocations(originalSyntax);
+ var generatorDiagnostics = new GeneratorDiagnosticsBag(
+ new DiagnosticDescriptorProvider(),
+ locations,
+ SR.ResourceManager,
+ typeof(FxResources.Microsoft.Interop.LibraryImportGenerator.SR));
+
+ // Process the LibraryImport attribute
+ LibraryImportCompilationData? libraryImportData = ProcessLibraryImportAttribute(libraryImportAttr);
+
+ // If we can't parse the attribute, we have an invalid compilation - stop processing
+ if (libraryImportData is null)
+ {
+ return generatorDiagnostics.Diagnostics.ToImmutableArray();
+ }
+
+ if (libraryImportData.IsUserDefined.HasFlag(InteropAttributeMember.StringMarshalling))
+ {
+ // User specified StringMarshalling.Custom without specifying StringMarshallingCustomType
+ if (libraryImportData.StringMarshalling == StringMarshalling.Custom && libraryImportData.StringMarshallingCustomType is null)
+ {
+ generatorDiagnostics.ReportInvalidStringMarshallingConfiguration(
+ libraryImportAttr, symbol.Name, SR.InvalidStringMarshallingConfigurationMissingCustomType);
+ }
+
+ // User specified something other than StringMarshalling.Custom while specifying StringMarshallingCustomType
+ if (libraryImportData.StringMarshalling != StringMarshalling.Custom && libraryImportData.StringMarshallingCustomType is not null)
+ {
+ generatorDiagnostics.ReportInvalidStringMarshallingConfiguration(
+ libraryImportAttr, symbol.Name, SR.InvalidStringMarshallingConfigurationNotCustom);
+ }
+ }
+
+ // Check for unsupported LCIDConversion attribute
+ INamedTypeSymbol? lcidConversionAttrType = environment.LcidConversionAttrType;
+ if (lcidConversionAttrType is not null)
+ {
+ foreach (AttributeData attr in symbol.GetAttributes())
+ {
+ if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, lcidConversionAttrType))
+ {
+ generatorDiagnostics.ReportConfigurationNotSupported(attr, nameof(TypeNames.LCIDConversionAttribute));
+ break;
+ }
+ }
+ }
+
+ // Create the signature context to collect marshalling-related diagnostics
+ var signatureContext = SignatureContext.Create(
+ symbol,
+ DefaultMarshallingInfoParser.Create(environment, generatorDiagnostics, symbol, libraryImportData, libraryImportAttr),
+ environment,
+ new CodeEmitOptions(SkipInit: true),
+ typeof(LibraryImportGenerator).Assembly);
+
+ // If forwarders are not being generated, we need to run stub generation logic to get those diagnostics too
+ if (!options.GenerateForwarders)
+ {
+ IMarshallingGeneratorResolver resolver = DefaultMarshallingGeneratorResolver.Create(
+ environment.EnvironmentFlags,
+ MarshalDirection.ManagedToUnmanaged,
+ TypeNames.LibraryImportAttribute_ShortName,
+ []);
+
+ // Check marshalling generators - this collects diagnostics for marshalling issues
+ _ = new ManagedToNativeStubGenerator(
+ signatureContext.ElementTypeInformation,
+ LibraryImportData.From(libraryImportData).SetLastError,
+ generatorDiagnostics,
+ resolver,
+ new CodeEmitOptions(SkipInit: true));
+ }
+
+ return generatorDiagnostics.Diagnostics.ToImmutableArray();
+ }
+
+ 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.
+ if (attrData.AttributeClass?.TypeKind is null or TypeKind.Error)
+ {
+ return null;
+ }
+
+ if (attrData.ConstructorArguments.Length == 0)
+ {
+ return null;
+ }
+
+ ImmutableDictionary namedArguments = ImmutableDictionary.CreateRange(attrData.NamedArguments);
+
+ string? entryPoint = null;
+ if (namedArguments.TryGetValue(nameof(LibraryImportCompilationData.EntryPoint), out TypedConstant entryPointValue))
+ {
+ if (entryPointValue.Value is not string)
+ {
+ return null;
+ }
+ entryPoint = (string)entryPointValue.Value!;
+ }
+
+ return new LibraryImportCompilationData(attrData.ConstructorArguments[0].Value!.ToString())
+ {
+ EntryPoint = entryPoint,
+ }.WithValuesFromNamedArguments(namedArguments);
+ }
+
+ ///
+ /// Checks if a method is invalid for generation and returns a diagnostic if so.
+ ///
+ /// A diagnostic if the method is invalid, null otherwise.
+ internal static DiagnosticInfo? GetDiagnosticIfInvalidMethodForGeneration(MethodDeclarationSyntax methodSyntax, IMethodSymbol method)
+ {
+ // Verify the method has no generic types or defined implementation
+ // and is marked static and partial.
+ if (methodSyntax.TypeParameterList is not null
+ || methodSyntax.Body is not null
+ || !methodSyntax.Modifiers.Any(SyntaxKind.StaticKeyword)
+ || !methodSyntax.Modifiers.Any(SyntaxKind.PartialKeyword))
+ {
+ return DiagnosticInfo.Create(GeneratorDiagnostics.InvalidAttributedMethodSignature, methodSyntax.Identifier.GetLocation(), method.Name);
+ }
+
+ // Verify that the types the method is declared in are marked partial.
+ if (methodSyntax.Parent is TypeDeclarationSyntax typeDecl && !typeDecl.IsInPartialContext(out var nonPartialIdentifier))
+ {
+ return DiagnosticInfo.Create(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers, methodSyntax.Identifier.GetLocation(), method.Name, nonPartialIdentifier);
+ }
+
+ // Verify the method does not have a ref return
+ if (method.ReturnsByRef || method.ReturnsByRefReadonly)
+ {
+ return DiagnosticInfo.Create(GeneratorDiagnostics.ReturnConfigurationNotSupported, methodSyntax.Identifier.GetLocation(), "ref return", method.ToDisplayString());
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Comparers.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Comparers.cs
index 87a565111f6b1e..bd0ecc1d889976 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Comparers.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Comparers.cs
@@ -13,10 +13,10 @@ namespace Microsoft.Interop
internal static class Comparers
{
///
- /// Comparer for an individual generated stub source as a syntax tree and the generated diagnostics for the stub.
+ /// Comparer for an individual generated stub source as a syntax tree.
///
- public static readonly IEqualityComparer<(MemberDeclarationSyntax Syntax, ImmutableArray Diagnostics)> GeneratedSyntax = new CustomValueTupleElementComparer>(SyntaxEquivalentComparer.Instance, new ImmutableArraySequenceEqualComparer(EqualityComparer.Default));
- }
+ public static readonly IEqualityComparer GeneratedSyntax = SyntaxEquivalentComparer.Instance;
+ }
///
/// Generic comparer to compare two instances element by element.
diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs
index bf0d61c87234c4..d8a98789882467 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs
@@ -28,8 +28,7 @@ internal sealed record IncrementalStubGenerationContext(
SequenceEqualImmutableArray ForwardedAttributes,
LibraryImportData LibraryImportData,
LibraryImportGeneratorOptions Options,
- EnvironmentFlags EnvironmentFlags,
- SequenceEqualImmutableArray Diagnostics);
+ EnvironmentFlags EnvironmentFlags);
public static class StepNames
{
@@ -39,8 +38,9 @@ public static class StepNames
public void Initialize(IncrementalGeneratorInitializationContext context)
{
- // Collect all methods adorned with LibraryImportAttribute
- var attributedMethods = context.SyntaxProvider
+ // Collect all methods adorned with LibraryImportAttribute and filter out invalid ones
+ // (diagnostics for invalid methods are reported by the analyzer)
+ var methodsToGenerate = context.SyntaxProvider
.ForAttributeWithMetadataName(
TypeNames.LibraryImportAttribute,
static (node, ct) => node is MethodDeclarationSyntax,
@@ -48,18 +48,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
? new { Syntax = (MethodDeclarationSyntax)context.TargetNode, Symbol = methodSymbol }
: null)
.Where(
- static modelData => modelData is not null);
-
- // Validate if attributed methods can have source generated
- var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) =>
- {
- DiagnosticInfo? diagnostic = GetDiagnosticIfInvalidMethodForGeneration(data.Syntax, data.Symbol);
- return diagnostic is not null
- ? DiagnosticOr<(MethodDeclarationSyntax Syntax, IMethodSymbol Symbol)>.From(diagnostic)
- : DiagnosticOr<(MethodDeclarationSyntax Syntax, IMethodSymbol Symbol)>.From((data.Syntax, data.Symbol));
- });
-
- var methodsToGenerate = context.FilterAndReportDiagnostics(methodsWithDiagnostics);
+ static modelData => modelData is not null
+ && Analyzers.LibraryImportDiagnosticsAnalyzer.GetDiagnosticIfInvalidMethodForGeneration(modelData.Syntax, modelData.Symbol) is null);
// Compute generator options
IncrementalValueProvider stubOptions = context.AnalyzerConfigOptionsProvider
@@ -67,23 +57,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
IncrementalValueProvider stubEnvironment = context.CreateStubEnvironmentProvider();
- // Validate environment that is being used to generate stubs.
- context.RegisterDiagnostics(
- context.CompilationProvider
- .Select((comp, ct) => comp.Options is CSharpCompilationOptions { AllowUnsafe: true })
- .Combine(attributedMethods.Collect())
- .SelectMany((data, ct) =>
- {
- if (data.Right.IsEmpty // no attributed methods
- || data.Left) // Unsafe code enabled
- {
- return ImmutableArray.Empty;
- }
-
- return ImmutableArray.Create(DiagnosticInfo.Create(GeneratorDiagnostics.RequiresAllowUnsafeBlocks, null));
- }));
-
- IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray)> generateSingleStub = methodsToGenerate
+ IncrementalValuesProvider generateSingleStub = methodsToGenerate
.Combine(stubEnvironment)
.Combine(stubOptions)
.Select(static (data, ct) => new
@@ -104,9 +78,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.WithComparer(Comparers.GeneratedSyntax)
.WithTrackingName(StepNames.GenerateSingleStub);
- context.RegisterDiagnostics(generateSingleStub.SelectMany((stubInfo, ct) => stubInfo.Item2));
-
- context.RegisterConcatenatedSyntaxOutputs(generateSingleStub.Select((data, ct) => data.Item1), "LibraryImports.g.cs");
+ context.RegisterConcatenatedSyntaxOutputs(generateSingleStub, "LibraryImports.g.cs");
}
private static List GenerateSyntaxForForwardedAttributes(AttributeData? suppressGCTransitionAttribute, AttributeData? unmanagedCallConvAttribute, AttributeData? defaultDllImportSearchPathsAttribute, AttributeData? wasmImportLinkageAttribute, AttributeData? stackTraceHiddenAttribute)
@@ -229,7 +201,6 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
- INamedTypeSymbol? lcidConversionAttrType = environment.LcidConversionAttrType;
INamedTypeSymbol? suppressGCTransitionAttrType = environment.SuppressGCTransitionAttrType;
INamedTypeSymbol? unmanagedCallConvAttrType = environment.UnmanagedCallConvAttrType;
INamedTypeSymbol? defaultDllImportSearchPathsAttrType = environment.DefaultDllImportSearchPathsAttrType;
@@ -237,7 +208,6 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
INamedTypeSymbol? stackTraceHiddenAttrType = environment.StackTraceHiddenAttrType;
// Get any attributes of interest on the method
AttributeData? generatedDllImportAttr = null;
- AttributeData? lcidConversionAttr = null;
AttributeData? suppressGCTransitionAttribute = null;
AttributeData? unmanagedCallConvAttribute = null;
AttributeData? defaultDllImportSearchPathsAttribute = null;
@@ -250,10 +220,6 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
{
generatedDllImportAttr = attr;
}
- else if (lcidConversionAttrType is not null && SymbolEqualityComparer.Default.Equals(attr.AttributeClass, lcidConversionAttrType))
- {
- lcidConversionAttr = attr;
- }
else if (suppressGCTransitionAttrType is not null && SymbolEqualityComparer.Default.Equals(attr.AttributeClass, suppressGCTransitionAttrType))
{
suppressGCTransitionAttribute = attr;
@@ -279,40 +245,20 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
Debug.Assert(generatedDllImportAttr is not null);
var locations = new MethodSignatureDiagnosticLocations(originalSyntax);
- var generatorDiagnostics = new GeneratorDiagnosticsBag(new DiagnosticDescriptorProvider(), locations, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.LibraryImportGenerator.SR));
// Process the LibraryImport attribute
LibraryImportCompilationData libraryImportData =
ProcessLibraryImportAttribute(generatedDllImportAttr!) ??
new LibraryImportCompilationData("INVALID_CSHARP_SYNTAX");
- if (libraryImportData.IsUserDefined.HasFlag(InteropAttributeMember.StringMarshalling))
- {
- // User specified StringMarshalling.Custom without specifying StringMarshallingCustomType
- if (libraryImportData.StringMarshalling == StringMarshalling.Custom && libraryImportData.StringMarshallingCustomType is null)
- {
- generatorDiagnostics.ReportInvalidStringMarshallingConfiguration(
- generatedDllImportAttr, symbol.Name, SR.InvalidStringMarshallingConfigurationMissingCustomType);
- }
-
- // User specified something other than StringMarshalling.Custom while specifying StringMarshallingCustomType
- if (libraryImportData.StringMarshalling != StringMarshalling.Custom && libraryImportData.StringMarshallingCustomType is not null)
- {
- generatorDiagnostics.ReportInvalidStringMarshallingConfiguration(
- generatedDllImportAttr, symbol.Name, SR.InvalidStringMarshallingConfigurationNotCustom);
- }
- }
-
- if (lcidConversionAttr is not null)
- {
- // Using LCIDConversion with LibraryImport is not supported
- generatorDiagnostics.ReportConfigurationNotSupported(lcidConversionAttr, nameof(TypeNames.LCIDConversionAttribute));
- }
+ // Create a diagnostics bag that discards all diagnostics.
+ // Diagnostics are now reported by the analyzer, not the generator.
+ var discardedDiagnostics = new GeneratorDiagnosticsBag(new DiagnosticDescriptorProvider(), locations, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.LibraryImportGenerator.SR));
// Create the stub.
var signatureContext = SignatureContext.Create(
symbol,
- DefaultMarshallingInfoParser.Create(environment, generatorDiagnostics, symbol, libraryImportData, generatedDllImportAttr),
+ DefaultMarshallingInfoParser.Create(environment, discardedDiagnostics, symbol, libraryImportData, generatedDllImportAttr),
environment,
new CodeEmitOptions(SkipInit: true),
typeof(LibraryImportGenerator).Assembly);
@@ -330,19 +276,16 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
new SequenceEqualImmutableArray(additionalAttributes.ToImmutableArray(), SyntaxEquivalentComparer.Instance),
LibraryImportData.From(libraryImportData),
options,
- environment.EnvironmentFlags,
- new SequenceEqualImmutableArray(generatorDiagnostics.Diagnostics.ToImmutableArray())
- );
+ environment.EnvironmentFlags);
}
- private static (MemberDeclarationSyntax, ImmutableArray) GenerateSource(
+ private static MemberDeclarationSyntax GenerateSource(
IncrementalStubGenerationContext pinvokeStub,
LibraryImportGeneratorOptions options)
{
- var diagnostics = new GeneratorDiagnosticsBag(new DiagnosticDescriptorProvider(), pinvokeStub.DiagnosticLocation, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.LibraryImportGenerator.SR));
if (options.GenerateForwarders)
{
- return (PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, explicitForwarding: true, pinvokeStub, diagnostics), pinvokeStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
+ return PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, pinvokeStub);
}
IMarshallingGeneratorResolver resolver = options.GenerateForwarders
@@ -350,10 +293,12 @@ private static (MemberDeclarationSyntax, ImmutableArray) Generat
: DefaultMarshallingGeneratorResolver.Create(pinvokeStub.EnvironmentFlags, MarshalDirection.ManagedToUnmanaged, TypeNames.LibraryImportAttribute_ShortName, []);
// Generate stub code
+ // Note: Diagnostics are now reported by the analyzer, so we pass a discarding diagnostics bag
+ var discardedDiagnostics = new GeneratorDiagnosticsBag(new DiagnosticDescriptorProvider(), pinvokeStub.DiagnosticLocation, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.LibraryImportGenerator.SR));
var stubGenerator = new ManagedToNativeStubGenerator(
pinvokeStub.SignatureContext.ElementTypeInformation,
pinvokeStub.LibraryImportData.SetLastError && !options.GenerateForwarders,
- diagnostics,
+ discardedDiagnostics,
resolver,
new CodeEmitOptions(SkipInit: true));
@@ -361,10 +306,7 @@ private static (MemberDeclarationSyntax, ImmutableArray) Generat
// This is done if the stub doesn't contain any marshalling logic.
if (stubGenerator.NoMarshallingRequired)
{
- // If we have any forwarded types, we're generating a "partial" stub.
- // In this case, we'll already emit errors for whatever type we failed to marshal.
- // So, don't emit additional errors for the stub itself.
- return (PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, explicitForwarding: false, pinvokeStub, diagnostics), pinvokeStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
+ return PrintForwarderStub(pinvokeStub.StubMethodSyntaxTemplate, pinvokeStub);
}
ImmutableArray forwardedAttributes = pinvokeStub.ForwardedAttributes.Array;
@@ -388,38 +330,22 @@ private static (MemberDeclarationSyntax, ImmutableArray) Generat
dllImport = dllImport.WithLeadingTrivia(Comment("// Local P/Invoke"));
code = code.AddStatements(dllImport);
- return (pinvokeStub.ContainingSyntaxContext.WrapMemberInContainingSyntaxWithUnsafeModifier(PrintGeneratedSource(pinvokeStub.StubMethodSyntaxTemplate, pinvokeStub.SignatureContext, code)), pinvokeStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
+ return pinvokeStub.ContainingSyntaxContext.WrapMemberInContainingSyntaxWithUnsafeModifier(PrintGeneratedSource(pinvokeStub.StubMethodSyntaxTemplate, pinvokeStub.SignatureContext, code));
}
- private static MemberDeclarationSyntax PrintForwarderStub(ContainingSyntax userDeclaredMethod, bool explicitForwarding, IncrementalStubGenerationContext stub, GeneratorDiagnosticsBag diagnostics)
+ private static MemberDeclarationSyntax PrintForwarderStub(ContainingSyntax userDeclaredMethod, IncrementalStubGenerationContext stub)
{
LibraryImportData pinvokeData = stub.LibraryImportData with { EntryPoint = stub.LibraryImportData.EntryPoint ?? userDeclaredMethod.Identifier.ValueText };
+ // Note: Diagnostics for forwarder issues are now reported by the analyzer
if (pinvokeData.IsUserDefined.HasFlag(InteropAttributeMember.StringMarshalling)
&& pinvokeData.StringMarshalling != StringMarshalling.Utf16)
{
- // Report a diagnostic when forwarding explicitly. Otherwise, StringMarshalling can just be omitted
- if (explicitForwarding)
- {
- diagnostics.ReportCannotForwardToDllImport(
- stub.DiagnosticLocation,
- $"{nameof(TypeNames.LibraryImportAttribute)}{Type.Delimiter}{nameof(StringMarshalling)}",
- $"{nameof(StringMarshalling)}{Type.Delimiter}{pinvokeData.StringMarshalling}");
- }
-
pinvokeData = pinvokeData with { IsUserDefined = pinvokeData.IsUserDefined & ~InteropAttributeMember.StringMarshalling };
}
if (pinvokeData.IsUserDefined.HasFlag(InteropAttributeMember.StringMarshallingCustomType))
{
- // Report a diagnostic when forwarding explicitly. Otherwise, StringMarshalling can just be omitted
- if (explicitForwarding)
- {
- diagnostics.ReportCannotForwardToDllImport(
- stub.DiagnosticLocation,
- $"{nameof(TypeNames.LibraryImportAttribute)}{Type.Delimiter}{nameof(InteropAttributeMember.StringMarshallingCustomType)}");
- }
-
pinvokeData = pinvokeData with { IsUserDefined = pinvokeData.IsUserDefined & ~InteropAttributeMember.StringMarshallingCustomType };
}
@@ -549,32 +475,5 @@ static ExpressionSyntax CreateEnumExpressionSyntax(T value) where T : Enum
IdentifierName(value.ToString()));
}
}
-
- private static DiagnosticInfo? GetDiagnosticIfInvalidMethodForGeneration(MethodDeclarationSyntax methodSyntax, IMethodSymbol method)
- {
- // Verify the method has no generic types or defined implementation
- // and is marked static and partial.
- if (methodSyntax.TypeParameterList is not null
- || methodSyntax.Body is not null
- || !methodSyntax.Modifiers.Any(SyntaxKind.StaticKeyword)
- || !methodSyntax.Modifiers.Any(SyntaxKind.PartialKeyword))
- {
- return DiagnosticInfo.Create(GeneratorDiagnostics.InvalidAttributedMethodSignature, methodSyntax.Identifier.GetLocation(), method.Name);
- }
-
- // Verify that the types the method is declared in are marked partial.
- if (methodSyntax.Parent is TypeDeclarationSyntax typeDecl && !typeDecl.IsInPartialContext(out var nonPartialIdentifier))
- {
- return DiagnosticInfo.Create(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers, methodSyntax.Identifier.GetLocation(), method.Name, nonPartialIdentifier);
- }
-
- // Verify the method does not have a ref return
- if (method.ReturnsByRef || method.ReturnsByRefReadonly)
- {
- return DiagnosticInfo.Create(GeneratorDiagnostics.ReturnConfigurationNotSupported, methodSyntax.Identifier.GetLocation(), "ref return", method.ToDisplayString());
- }
-
- return null;
- }
}
}
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
index 2c5c99b1cc1120..ba38c711698f7b 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CompilationExtensions.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CompilationExtensions.cs
@@ -18,7 +18,7 @@ public static EnvironmentFlags GetEnvironmentFlags(this Compilation compilation)
{
flags |= EnvironmentFlags.SkipLocalsInit;
}
- if (compilation.SourceModule.GetAttributes().Any(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute))
+ if (compilation.Assembly.GetAttributes().Any(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute))
{
flags |= EnvironmentFlags.DisableRuntimeMarshalling;
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs
index fdd2d33d6e7d27..3bd2bae74d92d0 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs
@@ -10,7 +10,7 @@
using Xunit;
using static Microsoft.Interop.UnitTests.TestUtils;
using StringMarshalling = System.Runtime.InteropServices.StringMarshalling;
-using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace ComInterfaceGenerator.Unit.Tests
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs
index 13d63a83333e2d..f07e6d16b6322d 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorDiagnostics.cs
@@ -7,7 +7,7 @@
using Microsoft.CodeAnalysis.Testing;
using Microsoft.Interop;
using Xunit;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace ComInterfaceGenerator.Unit.Tests
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs
index c00ff13aae59f3..c61e00b0a3d7e0 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComClassGeneratorOutputShape.cs
@@ -8,7 +8,7 @@
using Microsoft.CodeAnalysis.Testing;
using Xunit;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace ComInterfaceGenerator.Unit.Tests
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGeneratorOutputShape.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGeneratorOutputShape.cs
index efc4bc7f7c35f5..9ab81347a93dcb 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGeneratorOutputShape.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGeneratorOutputShape.cs
@@ -18,7 +18,7 @@
using SourceGenerators.Tests;
using Xunit;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace ComInterfaceGenerator.Unit.Tests
{
@@ -149,7 +149,7 @@ partial interface J : I
}
""";
- var test = new VerifyCompilationTest(false)
+ var test = new VerifyCompilationTest(false)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck,
@@ -198,7 +198,7 @@ partial interface K : J
}
""";
- var test = new VerifyCompilationTest(false)
+ var test = new VerifyCompilationTest(false)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck,
@@ -256,7 +256,7 @@ partial interface IDerivedIface : IFoo
}
""";
- var test = new VerifyCompilationTest(false)
+ var test = new VerifyCompilationTest(false)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck,
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs
index 3e959e4d2ac744..a908d720673dfc 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs
@@ -15,7 +15,7 @@
using Xunit;
using static Microsoft.Interop.UnitTests.TestUtils;
using StringMarshalling = System.Runtime.InteropServices.StringMarshalling;
-using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace ComInterfaceGenerator.Unit.Tests
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs
index ba4928fec1d367..b255a2a29a44df 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs
@@ -12,8 +12,8 @@
using Microsoft.CodeAnalysis.Testing;
using Microsoft.Interop.UnitTests;
using Xunit;
-using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
-using VerifyVTableGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyVTableGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace ComInterfaceGenerator.Unit.Tests
{
@@ -410,7 +410,7 @@ public partial interface MyOtherInterface : IMyInterface
}
""";
- var test = new VerifyCompilationTest(false)
+ var test = new VerifyCompilationTest(false)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck,
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/TargetSignatureTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/TargetSignatureTests.cs
index dbd18badbb78a7..2e7bb5815a27fd 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/TargetSignatureTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/TargetSignatureTests.cs
@@ -15,7 +15,7 @@
using Microsoft.Interop;
using Xunit;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace ComInterfaceGenerator.Unit.Tests
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/VerifyCompilationTest.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/VerifyCompilationTest.cs
index 09d6b5e2a58aed..39c9fb01f1add6 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/VerifyCompilationTest.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/VerifyCompilationTest.cs
@@ -3,12 +3,14 @@
using System;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.Interop.UnitTests;
namespace ComInterfaceGenerator.Unit.Tests
{
- internal class VerifyCompilationTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
+ internal class VerifyCompilationTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
where T : new()
+ where TAnalyzer : DiagnosticAnalyzer, new()
{
public required Action CompilationVerifier { get; init; }
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs
index 79c12e1d0de624..51b84dba0bc396 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs
@@ -40,6 +40,13 @@ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticRes
// Code fix tests support both analyzer and code fix testing. This test class is derived from the code fix test
// to avoid the need to maintain duplicate copies of the customization work.
internal class Test : CSharpCodeFixVerifier.Test
- { }
+ {
+ public Test() : base()
+ {
+ // Ignore compiler diagnostics since we're only testing the analyzer.
+ // Without the generator, partial methods won't have implementations which causes CS8795.
+ CompilerDiagnostics = CompilerDiagnostics.None;
+ }
+ }
}
}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs
index 3836d0243951e1..25dda49d840902 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs
@@ -2,6 +2,7 @@
// 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.Threading;
@@ -14,8 +15,9 @@
namespace Microsoft.Interop.UnitTests.Verifiers
{
- public static class CSharpSourceGeneratorVerifier
+ public static class CSharpSourceGeneratorVerifier
where TSourceGenerator : new()
+ where TAnalyzer : DiagnosticAnalyzer, new()
{
public static DiagnosticResult Diagnostic(string diagnosticId)
=> new DiagnosticResult(diagnosticId, DiagnosticSeverity.Error);
@@ -107,6 +109,9 @@ public Test(bool referenceAncillaryInterop)
SolutionTransforms.Add(CSharpVerifierHelper.GetAllDiagnosticsEnabledTransform(GetDiagnosticAnalyzers()));
}
+ protected override IEnumerable GetDiagnosticAnalyzers()
+ => [..base.GetDiagnosticAnalyzers(), new TAnalyzer()];
+
protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compilation compilation, ImmutableArray analyzers, AnalyzerOptions options, CancellationToken cancellationToken)
{
return new CompilationWithAnalyzers(
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs
index e54b6b77a1a1fc..4d8f362cd9b099 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs
@@ -10,7 +10,7 @@
using Microsoft.Interop;
using Xunit;
using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier<
- Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer,
+ Microsoft.Interop.Analyzers.LibraryImportDiagnosticsAnalyzer,
Microsoft.Interop.Analyzers.AddDisableRuntimeMarshallingAttributeFixer>;
namespace LibraryImportGenerator.UnitTests
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 e43937d75fa286..ebb295f6d3fe79 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs
@@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.Interop;
using Microsoft.Interop.UnitTests;
@@ -12,7 +13,7 @@
using System.Threading.Tasks;
using Xunit;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace LibraryImportGenerator.UnitTests
{
@@ -243,7 +244,7 @@ static class Marshaller
private static Task VerifyDownlevelSourceGeneratorAsync(string source, string typeName, string methodName, string? attributeName, bool attributeAdded, TestTargetFramework targetFramework)
{
- AttributeAddedTest test = new(typeName, methodName, attributeName, attributeAdded, targetFramework)
+ AttributeAddedTest test = new(typeName, methodName, attributeName, attributeAdded, targetFramework)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck
@@ -253,7 +254,7 @@ private static Task VerifyDownlevelSourceGeneratorAsync(string source, string ty
private static Task VerifySourceGeneratorAsync(string source, string typeName, string methodName, string? attributeName, bool attributeAdded)
{
- AttributeAddedTest test = new(typeName, methodName, attributeName, attributeAdded)
+ AttributeAddedTest test = new(typeName, methodName, attributeName, attributeAdded)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck
@@ -261,8 +262,9 @@ private static Task VerifySourceGeneratorAsync(string source, string typeName, s
return test.RunAsync();
}
- class AttributeAddedTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
+ class AttributeAddedTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
where TSourceGenerator : new()
+ where TAnalyzer : DiagnosticAnalyzer, new()
{
private readonly string _typeName;
private readonly string _methodName;
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 5a2b4ba19468f8..6a6de932786ad7 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs
@@ -12,7 +12,7 @@
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Xunit;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace LibraryImportGenerator.UnitTests
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs
index e632481d52109f..90787cb7a02bd7 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs
@@ -8,7 +8,7 @@
using Microsoft.Interop;
using Xunit;
using static Microsoft.Interop.UnitTests.TestUtils;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace LibraryImportGenerator.UnitTests
{
diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
index 952f8ef2890c81..8b6e94c043b7dc 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs
@@ -16,7 +16,7 @@
using Xunit;
using StringMarshalling = System.Runtime.InteropServices.StringMarshalling;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace LibraryImportGenerator.UnitTests
{
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 afa6af2bb4c9a6..225ae48288ebc1 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs
@@ -13,12 +13,13 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Text;
using Microsoft.DotNet.XUnitExtensions.Attributes;
using Microsoft.Interop.UnitTests;
using Xunit;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
namespace LibraryImportGenerator.UnitTests
{
@@ -578,7 +579,7 @@ public async Task ValidateSnippetsFallbackForwarder(string id, string source, Te
await test.RunAsync();
}
- class FallbackForwarderTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
+ class FallbackForwarderTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
{
private readonly bool _expectFallbackForwarder;
@@ -747,7 +748,7 @@ public async Task ValidateNoGeneratedOutputForNoImport()
public class Basic { }
""";
- var test = new NoChangeTest()
+ var test = new NoChangeTest()
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck
@@ -767,7 +768,7 @@ public async Task ValidateNoGeneratedOutputForNoImportDownlevel(TestTargetFramew
public class Basic { }
""";
- var test = new NoChangeTest(framework)
+ var test = new NoChangeTest(framework)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck
@@ -776,8 +777,9 @@ public class Basic { }
await test.RunAsync();
}
- class NoChangeTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
+ class NoChangeTest : Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test
where TSourceGenerator : new()
+ where TAnalyzer : DiagnosticAnalyzer, new()
{
public NoChangeTest()
: base(referenceAncillaryInterop: false)
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 e064a4b951d290..a440f935b7ffca 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs
@@ -14,7 +14,7 @@
using Xunit;
using StringMarshalling = Microsoft.Interop.StringMarshalling;
-using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier;
+using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpAnalyzerVerifier;
namespace LibraryImportGenerator.UnitTests
{
@@ -41,7 +41,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported)
.WithLocation(0)
.WithArguments("NS.MyClass", "c"),
@@ -71,7 +71,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupported)
.WithLocation(0)
.WithArguments("NS.MyClass", "Method1"),
@@ -93,7 +93,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails)
.WithLocation(0)
.WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "c"),
@@ -118,7 +118,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails)
.WithLocation(0)
.WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "Method1"),
@@ -143,7 +143,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.MarshalAsParameterConfigurationNotSupported)
.WithLocation(0)
.WithArguments(nameof(MarshalAsAttribute), "i1"),
@@ -170,7 +170,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.MarshalAsReturnConfigurationNotSupported)
.WithLocation(0)
.WithArguments(nameof(MarshalAsAttribute), "Method1"),
@@ -196,7 +196,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported)
.WithLocation(0)
.WithArguments(1, nameof(UnmanagedType)),
@@ -228,7 +228,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported)
.WithLocation(0)
.WithArguments($"{nameof(MarshalAsAttribute)}{Type.Delimiter}{nameof(MarshalAsAttribute.SafeArraySubType)}"),
@@ -269,7 +269,7 @@ public Native(string s) { }
.WithArguments($"{nameof(TypeNames.LibraryImportAttribute)}{Type.Delimiter}{nameof(StringMarshalling)}={nameof(StringMarshalling)}{Type.Delimiter}{nameof(StringMarshalling.Custom)}")
];
- var test = new Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test(TestTargetFramework.Standard2_0)
+ var test = new Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier.Test(TestTargetFramework.Standard2_0)
{
TestCode = source,
TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck
@@ -302,7 +302,7 @@ public Native(string s) { }
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidStringMarshallingConfiguration)
.WithLocation(0)
.WithArguments("Method1", "'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'."),
@@ -327,7 +327,7 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature)
.WithLocation(0)
.WithArguments("Method"),
@@ -349,13 +349,10 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature)
.WithLocation(0)
- .WithArguments("Method"),
- // Generator ignores the method
- DiagnosticResult.CompilerError("CS8795")
- .WithLocation(0));
+ .WithArguments("Method"));
}
[Fact]
@@ -374,18 +371,13 @@ partial class Test
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature)
.WithLocation(0)
.WithArguments("Method1"),
VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature)
.WithLocation(1)
- .WithArguments("Method2"),
- // Generator ignores the method
- DiagnosticResult.CompilerError("CS8795")
- .WithLocation(0),
- DiagnosticResult.CompilerError("CS8795")
- .WithLocation(1));
+ .WithArguments("Method2"));
}
[Theory]
@@ -404,16 +396,10 @@ public async Task NonPartialParentType_Diagnostic(string typeKind)
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers)
.WithLocation(0)
- .WithArguments("Method", "Test"),
- // Generator ignores the method
- DiagnosticResult.CompilerError("CS8795")
- .WithLocation(0),
- // Also expect CS0751: A partial method must be declared within a partial type
- DiagnosticResult.CompilerError("CS0751")
- .WithLocation(0));
+ .WithArguments("Method", "Test"));
}
[Theory]
@@ -435,7 +421,7 @@ partial class TestInner
}
""";
- await VerifyCS.VerifySourceGeneratorAsync(source,
+ await VerifyCS.VerifyAnalyzerAsync(source,
VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers)
.WithLocation(0)
.WithArguments("Method", "Test"));