From eb8e98ae271402ab1bdf47cc3510eb4bdf3b96b2 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 10 Apr 2023 15:27:41 -0700 Subject: [PATCH 01/17] Update references to Roslyn testing SDK and convert over our directed Diagnostic tests that target the live reference pack to use the test harness. --- eng/Versions.props | 2 +- .../tests/Common/TestUtils.cs | 2 - .../Verifiers/CSharpAnalyzerVerifier.cs | 2 +- .../Common/Verifiers/CSharpCodeFixVerifier.cs | 44 +-- .../CSharpSourceGeneratorVerifier.cs | 101 +++++ .../Common/Verifiers/CSharpVerifierHelper.cs | 53 ++- ...leRuntimeMarshallingAttributeFixerTests.cs | 2 +- .../AdditionalAttributesOnStub.cs | 1 - .../ConvertToLibraryImportAnalyzerTests.cs | 2 +- .../ConvertToLibraryImportFixerTests.cs | 3 +- .../CustomMarshallerAttributeFixerTest.cs | 2 +- ...allerAttributeFixerTests_AttributeUsage.cs | 2 +- ...StatefulLinearCollectionShapeValidation.cs | 2 +- ...FixerTests_StatefulValueShapeValidation.cs | 2 +- ...tatelessLinearCollectionShapeValidation.cs | 2 +- ...ixerTests_StatelessValueShapeValidation.cs | 2 +- .../Diagnostics.cs | 355 ++++++------------ .../LibraryImportGenerator.Unit.Tests.csproj | 3 + ...NativeMarshallingAttributeAnalyzerTests.cs | 2 +- .../ShapeBreakingDiagnosticSuppressorTests.cs | 2 +- 20 files changed, 297 insertions(+), 289 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs diff --git a/eng/Versions.props b/eng/Versions.props index 2ab51c280bbc6..1af4e614083ae 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -208,7 +208,7 @@ 2.45.0 - 1.1.2-beta1.22403.2 + 1.1.2-beta1.23205.1 7.0.0-preview-20221010.1 diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs index 81543e8b3d5d8..4d1ec3a5d2c7d 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs @@ -5,8 +5,6 @@ using Microsoft.CodeAnalysis.CSharp; 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/Common/Verifiers/CSharpAnalyzerVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs index 2ce99d0081a0f..08e29e3a5a2fb 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpAnalyzerVerifier.cs @@ -8,7 +8,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; -namespace LibraryImportGenerator.UnitTests.Verifiers +namespace Microsoft.Interop.UnitTests.Verifiers { public static class CSharpAnalyzerVerifier where TAnalyzer : DiagnosticAnalyzer, new() diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs index 00f03f13ec2fa..c2c86f075c193 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs @@ -14,9 +14,8 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.Interop.UnitTests; -namespace LibraryImportGenerator.UnitTests.Verifiers +namespace Microsoft.Interop.UnitTests.Verifiers { public static class CSharpCodeFixVerifier where TAnalyzer : DiagnosticAnalyzer, new() @@ -120,45 +119,8 @@ public Test() TestState.AdditionalReferences.AddRange(SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences()); TestState.AdditionalReferences.Add(TestUtils.GetAncillaryReference()); - SolutionTransforms.Add((solution, projectId) => - { - var project = solution.GetProject(projectId)!; - var compilationOptions = project.CompilationOptions!; - var diagnosticOptions = compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings); - - // Explicitly enable diagnostics that are not enabled by default - var enableAnalyzersOptions = new System.Collections.Generic.Dictionary(); - foreach (var analyzer in GetDiagnosticAnalyzers().ToImmutableArray()) - { - foreach (var diagnostic in analyzer.SupportedDiagnostics) - { - if (diagnostic.IsEnabledByDefault) - continue; - - // Map the default severity to the reporting behaviour. - // We cannot simply use ReportDiagnostic.Default here, as diagnostics that are not enabled by default - // are treated as suppressed (regardless of their default severity). - var report = diagnostic.DefaultSeverity switch - { - DiagnosticSeverity.Error => ReportDiagnostic.Error, - DiagnosticSeverity.Warning => ReportDiagnostic.Warn, - DiagnosticSeverity.Info => ReportDiagnostic.Info, - DiagnosticSeverity.Hidden => ReportDiagnostic.Hidden, - _ => ReportDiagnostic.Default - }; - enableAnalyzersOptions.Add(diagnostic.Id, report); - } - } - - compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( - compilationOptions.SpecificDiagnosticOptions - .SetItems(CSharpVerifierHelper.NullableWarnings) - .AddRange(enableAnalyzersOptions) - .AddRange(TestUtils.BindingRedirectWarnings)); - solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); - solution = solution.WithProjectParseOptions(projectId, ((CSharpParseOptions)project.ParseOptions!).WithLanguageVersion(LanguageVersion.Preview)); - return solution; - }); + SolutionTransforms.Add(CSharpVerifierHelper.GetAllDiagonsticsEnabledTransform(GetDiagnosticAnalyzers())); + SolutionTransforms.Add(CSharpVerifierHelper.SetPreviewLanguageVersion); } protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compilation compilation, ImmutableArray analyzers, AnalyzerOptions options, CancellationToken cancellationToken) diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs new file mode 100644 index 0000000000000..23fce81318e1d --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs @@ -0,0 +1,101 @@ +// 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.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.CSharp.Testing.XUnit; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Microsoft.Interop.UnitTests.Verifiers +{ + public static class CSharpSourceGeneratorVerifier + where TSourceGenerator : IIncrementalGenerator, new() + { + public static DiagnosticResult Diagnostic(string diagnosticId) + => new DiagnosticResult(diagnosticId, DiagnosticSeverity.Error); + + public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) + => new DiagnosticResult(descriptor); + + /// + /// Create a with the diagnostic message created with the provided arguments. + /// A with the property set instead of just the property + /// binds more strongly to the "correct" diagnostic as the test harness will match the diagnostic on the exact message instead of just on the message arguments. + /// + /// The diagnostic descriptor + /// The arguments to use to format the diagnostic message + /// A with a set with the 's message format and the . + public static DiagnosticResult DiagnosticWithArguments(DiagnosticDescriptor descriptor, params object[] arguments) + { + // Generate the specific message here to ensure a stronger match with the correct diagnostic. + return Diagnostic(descriptor).WithMessage(string.Format(descriptor.MessageFormat.ToString(), arguments)).WithArguments(arguments); + } + + /// + public static async Task VerifySourceGeneratorAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test(referenceAncillaryInterop: true) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + + internal class Test : CSharpSourceGeneratorTest + { + public Test(bool referenceAncillaryInterop) + { + // Clear out the default reference assemblies. We explicitly add references from the live ref pack, + // so we don't want the Roslyn test infrastructure to resolve/add any default reference assemblies + ReferenceAssemblies = new ReferenceAssemblies(string.Empty); + TestState.AdditionalReferences.AddRange(SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences()); + if (referenceAncillaryInterop) + { + TestState.AdditionalReferences.Add(TestUtils.GetAncillaryReference()); + } + + SolutionTransforms.Add(CSharpVerifierHelper.GetAllDiagonsticsEnabledTransform(GetDiagnosticAnalyzers())); + SolutionTransforms.Add(CSharpVerifierHelper.SetPreviewLanguageVersion); + } + + protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compilation compilation, ImmutableArray analyzers, AnalyzerOptions options, CancellationToken cancellationToken) + { + return new CompilationWithAnalyzers( + compilation, + analyzers, + new CompilationWithAnalyzersOptions( + options, + onAnalyzerException: null, + concurrentAnalysis: !Debugger.IsAttached, + logAnalyzerExecutionTime: true, + reportSuppressedDiagnostics: false, + analyzerExceptionFilter: ex => + { + // We're hunting down a intermittent issue that causes NullReferenceExceptions deep in Roslyn. To ensure that we get an actionable dump, we're going to FailFast here to force a process dump. + if (ex is NullReferenceException) + { + // Break a debugger here so there's a chance to investigate if someone is already attached. + if (System.Diagnostics.Debugger.IsAttached) + { + System.Diagnostics.Debugger.Break(); + } + Environment.FailFast($"Encountered a NullReferenceException while running an analyzer. Taking the process down to get an actionable crash dump. Exception information:{ex.ToString()}"); + } + return true; + })); + } + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs index 3d057d8f0139f..39521167a1fdb 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs @@ -2,11 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; -namespace LibraryImportGenerator.UnitTests.Verifiers +namespace Microsoft.Interop.UnitTests.Verifiers { internal static class CSharpVerifierHelper { @@ -25,5 +28,53 @@ private static ImmutableDictionary GetNullableWarnings var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory); return commandLineArguments.CompilationOptions.SpecificDiagnosticOptions; } + + internal static Func GetAllDiagonsticsEnabledTransform(IEnumerable analyzers) + { + return (solution, projectId) => + { + var project = solution.GetProject(projectId)!; + var compilationOptions = project.CompilationOptions!; + var diagnosticOptions = compilationOptions.SpecificDiagnosticOptions.SetItems(NullableWarnings); + + // Explicitly enable diagnostics that are not enabled by default + var enableAnalyzersOptions = new Dictionary(); + foreach (var analyzer in analyzers) + { + foreach (var diagnostic in analyzer.SupportedDiagnostics) + { + if (diagnostic.IsEnabledByDefault) + continue; + + // Map the default severity to the reporting behaviour. + // We cannot simply use ReportDiagnostic.Default here, as diagnostics that are not enabled by default + // are treated as suppressed (regardless of their default severity). + var report = diagnostic.DefaultSeverity switch + { + DiagnosticSeverity.Error => ReportDiagnostic.Error, + DiagnosticSeverity.Warning => ReportDiagnostic.Warn, + DiagnosticSeverity.Info => ReportDiagnostic.Info, + DiagnosticSeverity.Hidden => ReportDiagnostic.Hidden, + _ => ReportDiagnostic.Default + }; + enableAnalyzersOptions.Add(diagnostic.Id, report); + } + } + + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions + .SetItems(NullableWarnings) + .AddRange(enableAnalyzersOptions) + .AddRange(TestUtils.BindingRedirectWarnings)); + solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); + return solution; + }; + } + + internal static Solution SetPreviewLanguageVersion(Solution solution, ProjectId projectId) + { + var project = solution.GetProject(projectId)!; + return solution.WithProjectParseOptions(projectId, ((CSharpParseOptions)project.ParseOptions!).WithLanguageVersion(LanguageVersion.Preview)); + } } } 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 8ae6c15d27924..525afdfbf71e2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs @@ -18,7 +18,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.Interop; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< LibraryImportGenerator.UnitTests.AddDisableRuntimeMarshallingAttributeFixerTests.MockAnalyzer, Microsoft.Interop.Analyzers.AddDisableRuntimeMarshallingAttributeFixer>; using Xunit; 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 484901a71fe99..1c81253b5d166 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop.UnitTests; using SourceGenerators.Tests; using System.Collections.Generic; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs index 580683b480f2f..d2bd400584f2f 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportAnalyzerTests.cs @@ -10,7 +10,7 @@ using static Microsoft.Interop.Analyzers.ConvertToLibraryImportAnalyzer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpAnalyzerVerifier; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpAnalyzerVerifier; namespace LibraryImportGenerator.UnitTests { diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs index e9ef9e0fe7d58..239bad31be4ac 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ConvertToLibraryImportFixerTests.cs @@ -9,9 +9,8 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.Interop.Analyzers; using Xunit; -using static Microsoft.Interop.Analyzers.ConvertToLibraryImportFixer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< Microsoft.Interop.Analyzers.ConvertToLibraryImportAnalyzer, Microsoft.Interop.Analyzers.ConvertToLibraryImportFixer>; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTest.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTest.cs index c56b8aa792f21..2380a0b9d8b4a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTest.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTest.cs @@ -8,7 +8,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -using LibraryImportGenerator.UnitTests.Verifiers; +using Microsoft.Interop.UnitTests.Verifiers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop.Analyzers; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_AttributeUsage.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_AttributeUsage.cs index c846550b7c10b..03775e7aef3a1 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_AttributeUsage.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_AttributeUsage.cs @@ -8,7 +8,7 @@ using Xunit; using static Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer, Microsoft.Interop.Analyzers.CustomMarshallerAttributeFixer>; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulLinearCollectionShapeValidation.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulLinearCollectionShapeValidation.cs index 62d599fea5494..c2fc65ead881f 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulLinearCollectionShapeValidation.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulLinearCollectionShapeValidation.cs @@ -9,7 +9,7 @@ using Xunit; using static Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer, Microsoft.Interop.Analyzers.CustomMarshallerAttributeFixer>; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulValueShapeValidation.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulValueShapeValidation.cs index 6cf2b96e61912..b8dbae8e318d8 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulValueShapeValidation.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatefulValueShapeValidation.cs @@ -10,7 +10,7 @@ using Xunit; using static Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer, Microsoft.Interop.Analyzers.CustomMarshallerAttributeFixer>; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessLinearCollectionShapeValidation.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessLinearCollectionShapeValidation.cs index 28149a0f7864e..e4b4b63778ed7 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessLinearCollectionShapeValidation.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessLinearCollectionShapeValidation.cs @@ -9,7 +9,7 @@ using Xunit; using static Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer, Microsoft.Interop.Analyzers.CustomMarshallerAttributeFixer>; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessValueShapeValidation.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessValueShapeValidation.cs index b855690efc2b3..6fcc90dae43dd 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessValueShapeValidation.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CustomMarshallerAttributeFixerTests_StatelessValueShapeValidation.cs @@ -9,7 +9,7 @@ using Xunit; using static Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpCodeFixVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< Microsoft.Interop.Analyzers.CustomMarshallerAttributeAnalyzer, Microsoft.Interop.Analyzers.CustomMarshallerAttributeFixer>; 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 63119dd4a8d61..ae473617af028 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs @@ -15,6 +15,7 @@ using Xunit; using StringMarshalling = Microsoft.Interop.StringMarshalling; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; namespace LibraryImportGenerator.UnitTests { @@ -34,29 +35,20 @@ class MyClass { } partial class Test { [LibraryImport("DoesNotExist")] - public static partial void Method1(NS.MyClass c); + public static partial void Method1(NS.MyClass {|#0:c|}); [LibraryImport("DoesNotExist")] - public static partial void Method2(int i, List list); + public static partial void Method2(int i, List {|#1:list|}); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupported)) - .WithSpan(11, 51, 11, 52) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported) + .WithLocation(0) .WithArguments("NS.MyClass", "c"), - (new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupported)) - .WithSpan(14, 57, 14, 61) - .WithArguments("System.Collections.Generic.List", "list"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported) + .WithLocation(1) + .WithArguments("System.Collections.Generic.List", "list")); } [Fact] @@ -73,29 +65,20 @@ class MyClass { } partial class Test { [LibraryImport("DoesNotExist")] - public static partial NS.MyClass Method1(); + public static partial NS.MyClass {|#0:Method1|}(); [LibraryImport("DoesNotExist")] - public static partial List Method2(); + public static partial List {|#1:Method2|}(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ReturnTypeNotSupported)) - .WithSpan(11, 38, 11, 45) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupported) + .WithLocation(0) .WithArguments("NS.MyClass", "Method1"), - (new DiagnosticResult(GeneratorDiagnostics.ReturnTypeNotSupported)) - .WithSpan(14, 37, 14, 44) - .WithArguments("System.Collections.Generic.List", "Method2"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupported) + .WithLocation(1) + .WithArguments("System.Collections.Generic.List", "Method2")); } [Fact] @@ -107,24 +90,17 @@ public async Task ParameterTypeNotSupportedWithDetails_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - public static partial void Method(char c, string s); + public static partial void Method(char {|#0:c|}, string {|#1:s|}); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails)) - .WithSpan(6, 44, 6, 45), - (new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails)) - .WithSpan(6, 54, 6, 55), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + await VerifyCS.VerifySourceGeneratorAsync(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"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "s")); } [Fact] @@ -136,27 +112,20 @@ public async Task ReturnTypeNotSupportedWithDetails_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - public static partial char Method1(); + public static partial char {|#0:Method1|}(); [LibraryImport("DoesNotExist")] - public static partial string Method2(); + public static partial string {|#1:Method2|}(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails)) - .WithSpan(6, 32, 6, 39), - (new DiagnosticResult(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails)) - .WithSpan(9, 34, 9, 41), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + await VerifyCS.VerifySourceGeneratorAsync(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"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "Method2")); } [Fact] @@ -168,29 +137,20 @@ public async Task ParameterConfigurationNotSupported_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - public static partial void Method1([MarshalAs(UnmanagedType.BStr)] int i1, int i2); + public static partial void Method1([MarshalAs(UnmanagedType.BStr)] int {|#0:i1|}, int i2); [LibraryImport("DoesNotExist")] - public static partial void Method2(int i1, [MarshalAs(UnmanagedType.FunctionPtr)] bool b2); + public static partial void Method2(int i1, [MarshalAs(UnmanagedType.FunctionPtr)] bool {|#1:b2|}); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ParameterConfigurationNotSupported)) - .WithSpan(6, 76, 6, 78) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(0) .WithArguments(nameof(MarshalAsAttribute), "i1"), - (new DiagnosticResult(GeneratorDiagnostics.ParameterConfigurationNotSupported)) - .WithSpan(9, 92, 9, 94) - .WithArguments(nameof(MarshalAsAttribute), "b2"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(1) + .WithArguments(nameof(MarshalAsAttribute), "b2")); } [Fact] @@ -203,30 +163,21 @@ partial class Test { [LibraryImport("DoesNotExist")] [return: MarshalAs(UnmanagedType.BStr)] - public static partial int Method1(int i); + public static partial int {|#0:Method1|}(int i); [LibraryImport("DoesNotExist")] [return: MarshalAs(UnmanagedType.FunctionPtr)] - public static partial bool Method2(int i); + public static partial bool {|#1:Method2|}(int i); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ReturnConfigurationNotSupported)) - .WithSpan(7, 31, 7, 38) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(0) .WithArguments(nameof(MarshalAsAttribute), "Method1"), - (new DiagnosticResult(GeneratorDiagnostics.ReturnConfigurationNotSupported)) - .WithSpan(11, 32, 11, 39) - .WithArguments(nameof(MarshalAsAttribute), "Method2"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(1) + .WithArguments(nameof(MarshalAsAttribute), "Method2")); } [Fact] @@ -238,36 +189,27 @@ public async Task MarshalAsUnmanagedTypeNotSupported_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - [return: MarshalAs(1)] - public static partial int Method1(int i); + [return: {|#0:MarshalAs(1)|}] + public static partial int {|#1:Method1|}(int i); [LibraryImport("DoesNotExist")] - public static partial int Method2([MarshalAs((short)0)] bool b); + public static partial int Method2([{|#2:MarshalAs((short)0)|}] bool {|#3:b|}); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ConfigurationValueNotSupported)) - .WithSpan(6, 14, 6, 26) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(0) .WithArguments(1, nameof(UnmanagedType)), - (new DiagnosticResult(GeneratorDiagnostics.ReturnConfigurationNotSupported)) - .WithSpan(7, 31, 7, 38) + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(1) .WithArguments(nameof(MarshalAsAttribute), "Method1"), - (new DiagnosticResult(GeneratorDiagnostics.ConfigurationValueNotSupported)) - .WithSpan(10, 40, 10, 59) + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(2) .WithArguments(0, nameof(UnmanagedType)), - (new DiagnosticResult(GeneratorDiagnostics.ParameterConfigurationNotSupported)) - .WithSpan(10, 66, 10, 67) - .WithArguments(nameof(MarshalAsAttribute), "b"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(3) + .WithArguments(nameof(MarshalAsAttribute), "b")); } [Fact] @@ -279,29 +221,21 @@ public async Task MarshalAsFieldNotSupported_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - [return: MarshalAs(UnmanagedType.I4, SafeArraySubType=VarEnum.VT_I4)] + [return: {|#0:MarshalAs(UnmanagedType.I4, SafeArraySubType=VarEnum.VT_I4)|}] public static partial int Method1(int i); [LibraryImport("DoesNotExist")] - public static partial int Method2([MarshalAs(UnmanagedType.I1, IidParameterIndex = 1)] bool b); + public static partial int Method2([{|#1:MarshalAs(UnmanagedType.I1, IidParameterIndex = 1)|}] bool b); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.ConfigurationNotSupported)) - .WithSpan(6, 14, 6, 73) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(0) .WithArguments($"{nameof(MarshalAsAttribute)}{Type.Delimiter}{nameof(MarshalAsAttribute.SafeArraySubType)}"), - (new DiagnosticResult(GeneratorDiagnostics.ConfigurationNotSupported)) - .WithSpan(10, 40, 10, 90) - .WithArguments($"{nameof(MarshalAsAttribute)}{Type.Delimiter}{nameof(MarshalAsAttribute.IidParameterIndex)}"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(1) + .WithArguments($"{nameof(MarshalAsAttribute)}{Type.Delimiter}{nameof(MarshalAsAttribute.IidParameterIndex)}")); } [Fact] @@ -337,10 +271,10 @@ public Native(string s) { } new Microsoft.Interop.LibraryImportGenerator()); DiagnosticResult[] expectedDiags = new DiagnosticResult[] { - (new DiagnosticResult(GeneratorDiagnostics.CannotForwardToDllImport)) + VerifyCS.Diagnostic(GeneratorDiagnostics.CannotForwardToDllImport) .WithSpan(6, 32, 6, 39) .WithArguments($"{nameof(TypeNames.LibraryImportAttribute)}{Type.Delimiter}{nameof(StringMarshalling)}={nameof(StringMarshalling)}{Type.Delimiter}{nameof(StringMarshalling.Utf8)}"), - (new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails)) + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) .WithSpan(9, 47, 9, 48) }; VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); @@ -357,10 +291,10 @@ public async Task InvalidStringMarshallingConfiguration_ReportsDiagnostic() {{CodeSnippets.DisableRuntimeMarshalling}} partial class Test { - [LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.Custom)] + [{|#0:LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.Custom)|}] public static partial void Method1(out int i); - [LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.Utf8, StringMarshallingCustomType = typeof(Native))] + [{|#1:LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.Utf8, StringMarshallingCustomType = typeof(Native))|}] public static partial void Method2(out int i); struct Native @@ -371,20 +305,14 @@ public Native(string s) { } } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.InvalidStringMarshallingConfiguration)) - .WithSpan(6, 6, 6, 81), - (new DiagnosticResult(GeneratorDiagnostics.InvalidStringMarshallingConfiguration)) - .WithSpan(9, 6, 9, 125) - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidStringMarshallingConfiguration) + .WithLocation(0) + .WithArguments("Method1", "'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'."), + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidStringMarshallingConfiguration) + .WithLocation(1) + .WithArguments("Method2", "'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified.")); } [Fact] @@ -396,28 +324,20 @@ public async Task NonPartialMethod_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - public static void Method() { } + public static void {|#0:Method|}() { } [LibraryImport("DoesNotExist")] - public static extern void ExternMethod(); + public static extern void {|#1:ExternMethod|}(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedMethodSignature)) - .WithSpan(6, 24, 6, 30) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature) + .WithLocation(0) .WithArguments("Method"), - (new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedMethodSignature)) - .WithSpan(9, 31, 9, 43) - .WithArguments("ExternMethod"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature) + .WithLocation(1) + .WithArguments("ExternMethod")); } [Fact] @@ -429,23 +349,17 @@ public async Task NonStaticMethod_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - public partial void Method(); + public partial void {|#0:Method|}(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedMethodSignature)) - .WithSpan(6, 25, 6, 31) - .WithArguments("Method") - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - // Generator ignores the method - TestUtils.AssertPreSourceGeneratorCompilation(newComp); + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature) + .WithLocation(0) + .WithArguments("Method"), + // Generator ignores the method + DiagnosticResult.CompilerError("CS8795") + .WithLocation(0)); } [Fact] @@ -457,29 +371,25 @@ public async Task GenericMethod_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist")] - public static partial void Method1(); + public static partial void {|#0:Method1|}(); [LibraryImport("DoesNotExist")] - public static partial void Method2(); + public static partial void {|#1:Method2|}(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedMethodSignature)) - .WithSpan(6, 32, 6, 39) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature) + .WithLocation(0) .WithArguments("Method1"), - (new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedMethodSignature)) - .WithSpan(9, 32, 9, 39) + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodSignature) + .WithLocation(1) .WithArguments("Method2"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - // Generator ignores the method - TestUtils.AssertPreSourceGeneratorCompilation(newComp); + // Generator ignores the method + DiagnosticResult.CompilerError("CS8795") + .WithLocation(0), + DiagnosticResult.CompilerError("CS8795") + .WithLocation(1)); } [Theory] @@ -494,26 +404,20 @@ public async Task NonPartialParentType_Diagnostic(string typeKind) {{typeKind}} Test { [LibraryImport("DoesNotExist")] - public static partial void Method(); + public static partial void {|#0:Method|}(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - // Also expect CS0751: A partial method must be declared within a partial type - string additionalDiag = "CS0751"; - TestUtils.AssertPreSourceGeneratorCompilation(comp, additionalDiag); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers)) - .WithSpan(6, 32, 6, 38) + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers) + .WithLocation(0) .WithArguments("Method", "Test"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - - // Generator ignores the method - TestUtils.AssertPreSourceGeneratorCompilation(newComp, additionalDiag); + // 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)); } [Theory] @@ -530,24 +434,15 @@ public async Task NonPartialGrandparentType_Diagnostic(string typeKind) partial class TestInner { [LibraryImport("DoesNotExist")] - static partial void Method(); + static partial void {|#0:Method|}(); } } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - DiagnosticResult[] expectedDiags = new DiagnosticResult[] - { - (new DiagnosticResult(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers)) - .WithSpan(8, 29, 8, 35) - .WithArguments("Method", "Test"), - }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - // Generator ignores the method - TestUtils.AssertPreSourceGeneratorCompilation(newComp); + await VerifyCS.VerifySourceGeneratorAsync(source, + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers) + .WithLocation(0) + .WithArguments("Method", "Test")); } private static void VerifyDiagnostics(DiagnosticResult[] expectedDiagnostics, Diagnostic[] actualDiagnostics) 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 1c25ff00a281d..9695eba3d8bda 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 @@ -31,6 +31,8 @@ Link="Verifiers\CSharpAnalyzerVerifier.cs"/> + @@ -39,6 +41,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs index 5b8769e19c9ee..ea3bcef8860a4 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/NativeMarshallingAttributeAnalyzerTests.cs @@ -8,7 +8,7 @@ using Xunit; using static Microsoft.Interop.Analyzers.NativeMarshallingAttributeAnalyzer; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpAnalyzerVerifier< +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpAnalyzerVerifier< Microsoft.Interop.Analyzers.NativeMarshallingAttributeAnalyzer>; namespace LibraryImportGenerator.UnitTests diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ShapeBreakingDiagnosticSuppressorTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ShapeBreakingDiagnosticSuppressorTests.cs index bcdbe7cf8be8e..820112ccb93eb 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ShapeBreakingDiagnosticSuppressorTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ShapeBreakingDiagnosticSuppressorTests.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using LibraryImportGenerator.UnitTests.Verifiers; +using Microsoft.Interop.UnitTests.Verifiers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; From aab1da5d5664501e0b7c2fe76262b179a55ad550 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 10 Apr 2023 15:38:00 -0700 Subject: [PATCH 02/17] Add mechansim to test downlevel tfms with test harness and convert outerloop diagnostics tests to use the harness. --- .../CSharpSourceGeneratorVerifier.cs | 26 ++++++++++++++--- .../Diagnostics.cs | 29 +++++++++---------- 2 files changed, 35 insertions(+), 20 deletions(-) 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 23fce81318e1d..5b0e4927da78a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs @@ -55,12 +55,30 @@ public static async Task VerifySourceGeneratorAsync(string source, params Diagno internal class Test : CSharpSourceGeneratorTest { + public Test(TestTargetFramework targetFramework) + { + if (targetFramework == TestTargetFramework.Net) + { + // Clear out the default reference assemblies. We explicitly add references from the live ref pack, + // so we don't want the Roslyn test infrastructure to resolve/add any default reference assemblies + ReferenceAssemblies = new ReferenceAssemblies(string.Empty); + TestState.AdditionalReferences.AddRange(SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences()); + } + else + { + ReferenceAssemblies = targetFramework switch + { + TestTargetFramework.Framework => ReferenceAssemblies.NetFramework.Net48.Default, + TestTargetFramework.Standard => ReferenceAssemblies.NetStandard.NetStandard21, + TestTargetFramework.Core => ReferenceAssemblies.NetCore.NetCoreApp31, + TestTargetFramework.Net6 => ReferenceAssemblies.Net.Net60, + _ => ReferenceAssemblies.Default + }; + } + } public Test(bool referenceAncillaryInterop) + :this(TestTargetFramework.Net) { - // Clear out the default reference assemblies. We explicitly add references from the live ref pack, - // so we don't want the Roslyn test infrastructure to resolve/add any default reference assemblies - ReferenceAssemblies = new ReferenceAssemblies(string.Empty); - TestState.AdditionalReferences.AddRange(SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences()); if (referenceAncillaryInterop) { TestState.AdditionalReferences.Add(TestUtils.GetAncillaryReference()); 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 ae473617af028..de4081cd5aaba 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs @@ -248,10 +248,10 @@ public async Task StringMarshallingForwardingNotSupported_ReportsDiagnostic() partial class Test { [LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.Utf8)] - public static partial void Method1(string s); + public static partial void {|#0:Method1|}(string s); [LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Native))] - public static partial void Method2(string s); + public static partial void Method2(string {|#1:s|}); struct Native { @@ -260,26 +260,23 @@ public Native(string s) { } } } """ + CodeSnippets.LibraryImportAttributeDeclaration; - - // Compile against Standard so that we generate forwarders - Compilation comp = await TestUtils.CreateCompilation(source, TestTargetFramework.Standard); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - Compilation newComp = TestUtils.RunGenerators( - comp, - new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(TestTargetFramework.Standard)), - out var generatorDiags, - new Microsoft.Interop.LibraryImportGenerator()); DiagnosticResult[] expectedDiags = new DiagnosticResult[] { VerifyCS.Diagnostic(GeneratorDiagnostics.CannotForwardToDllImport) - .WithSpan(6, 32, 6, 39) + .WithLocation(0) .WithArguments($"{nameof(TypeNames.LibraryImportAttribute)}{Type.Delimiter}{nameof(StringMarshalling)}={nameof(StringMarshalling)}{Type.Delimiter}{nameof(StringMarshalling.Utf8)}"), VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithSpan(9, 47, 9, 48) + .WithLocation(1) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "s") + }; + + var test = new VerifyCS.Test(TestTargetFramework.Standard) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck }; - VerifyDiagnostics(expectedDiags, GetSortedDiagnostics(generatorDiags)); - var newCompDiags = newComp.GetDiagnostics(); - Assert.Empty(newCompDiags); + test.ExpectedDiagnostics.AddRange(expectedDiags); + await test.RunAsync(); } [Fact] From adfbff44fe2c94c128f795e8e3efa0146463e99c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 10 Apr 2023 16:43:07 -0700 Subject: [PATCH 03/17] Change the AddDisableRuntimeMarshallingAttributeFixer test suite to use the actual generator with the testing SDK as it now supports testing source generators with code fixers in a single test. --- ...leRuntimeMarshallingAttributeFixerTests.cs | 82 ++++++------------- 1 file changed, 24 insertions(+), 58 deletions(-) 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 525afdfbf71e2..92a6aab6b177b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs @@ -4,25 +4,15 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing.Model; -using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.Interop.Analyzers; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.Interop; +using Xunit; +using System.IO; using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpCodeFixVerifier< - LibraryImportGenerator.UnitTests.AddDisableRuntimeMarshallingAttributeFixerTests.MockAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer, Microsoft.Interop.Analyzers.AddDisableRuntimeMarshallingAttributeFixer>; -using Xunit; -using System.IO; namespace LibraryImportGenerator.UnitTests { @@ -38,7 +28,7 @@ public static async Task Adds_NewFile_With_Attribute() partial class Foo { [LibraryImport("Foo")] - public static partial void {|CS8795:PInvoke|}(S {|#0:s|}); + public static partial void PInvoke(S {|#0:s|}); } [NativeMarshalling(typeof(Marshaller))] @@ -48,6 +38,7 @@ struct S struct Native { + public bool b; } [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] @@ -60,7 +51,9 @@ static class Marshaller """; var expectedPropertiesFile = "[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling]" + Environment.NewLine; - var diagnostic = VerifyCS.Diagnostic(GeneratorDiagnostics.Ids.TypeNotSupported).WithLocation(0).WithArguments("S", "s"); + var diagnostic = 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.", "s"); await VerifyCodeFixAsync(source, propertiesFile: null, expectedPropertiesFile, diagnostic); } @@ -73,7 +66,7 @@ public static async Task Appends_Attribute_To_Existing_AssemblyInfo_File() partial class Foo { [LibraryImport("Foo")] - public static partial void {|CS8795:PInvoke|}(S {|#0:s|}); + public static partial void PInvoke(S {|#0:s|}); } [NativeMarshalling(typeof(Marshaller))] @@ -83,6 +76,7 @@ struct S struct Native { + public bool b; } [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))] @@ -106,19 +100,21 @@ static class Marshaller """; - var diagnostic = VerifyCS.Diagnostic(GeneratorDiagnostics.Ids.TypeNotSupported).WithLocation(0).WithArguments("S", "s"); + var diagnostic = 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.", "s"); await VerifyCodeFixAsync(source, propertiesFile, expectedPropertiesFile, diagnostic); } private static async Task VerifyCodeFixAsync(string source, string? propertiesFile, string? expectedPropertiesFile, DiagnosticResult diagnostic) { - var test = new Test(); - // We don't care about validating the settings for the MockAnalyzer and we're also hitting failures on Mono - // with this check in this case, so skip the check for now. - test.TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck; - test.TestCode = source; - test.FixedCode = source; - test.BatchFixedCode = source; + var test = new Test + { + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, + TestCode = source, + FixedCode = source, + BatchFixedCode = source + }; test.ExpectedDiagnostics.Add(diagnostic); if (propertiesFile is not null) { @@ -134,45 +130,15 @@ private static async Task VerifyCodeFixAsync(string source, string? propertiesFi class Test : VerifyCS.Test { + private static readonly ImmutableArray GeneratorTypes = ImmutableArray.Create(typeof(Microsoft.Interop.LibraryImportGenerator)); + public const string FilePathPrefix = "/Project/"; protected override string DefaultFilePathPrefix => FilePathPrefix; - } - - // The Roslyn SDK doesn't provide a good test harness for testing a code fix that triggers - // on a source-generator-introduced diagnostic. This analyzer does a decent enough job of triggering - // the specific diagnostic in the right place for us to test the code fix. - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class MockAnalyzer : DiagnosticAnalyzer - { - private static readonly DiagnosticDescriptor AddDisableRuntimeMarshallingAttributeRule = GeneratorDiagnostics.ParameterTypeNotSupported; - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(AddDisableRuntimeMarshallingAttributeRule); - - public override void Initialize(AnalysisContext context) + protected override IEnumerable GetSourceGenerators() { - context.EnableConcurrentExecution(); - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - context.RegisterSymbolAction(context => - { - var symbol = (IParameterSymbol)context.Symbol; - - if (context.Symbol.ContainingAssembly.GetAttributes().Any(attr => attr.AttributeClass!.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute)) - { - return; - } - - if (symbol.ContainingSymbol is IMethodSymbol { IsStatic: true, IsPartialDefinition: true }) - { - context.ReportDiagnostic(context.Symbol.CreateDiagnostic( - AddDisableRuntimeMarshallingAttributeRule, - ImmutableDictionary.Empty - .Add( - GeneratorDiagnosticProperties.AddDisableRuntimeMarshallingAttribute, - GeneratorDiagnosticProperties.AddDisableRuntimeMarshallingAttribute), - symbol.Type.ToDisplayString(), symbol.Name)); - } - }, SymbolKind.Parameter); + return GeneratorTypes; } } } From 81cb7611631bf56e565d10ee960b4b735a8fe592 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 11 Apr 2023 11:42:00 -0700 Subject: [PATCH 04/17] Set up the correct options in an editorconfig for target framework based on a given test's requested tfm. --- .../CSharpSourceGeneratorVerifier.cs | 1 + .../Common/Verifiers/CSharpVerifierHelper.cs | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) 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 5b0e4927da78a..58a4546d9d174 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs @@ -75,6 +75,7 @@ public Test(TestTargetFramework targetFramework) _ => ReferenceAssemblies.Default }; } + SolutionTransforms.Add(CSharpVerifierHelper.GetTargetFrameworkAnalyzerOptionsProviderTransform(targetFramework)); } public Test(bool referenceAncillaryInterop) :this(TestTargetFramework.Net) diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs index 39521167a1fdb..15a88f89a798e 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.Interop.UnitTests.Verifiers { @@ -71,6 +72,42 @@ internal static Func GetAllDiagonsticsEnabledTran }; } + internal static Func GetTargetFrameworkAnalyzerOptionsProviderTransform(TestTargetFramework targetFramework) + { + return (solution, projectId) => + { + var project = solution.GetProject(projectId)!; + string tfmEditorConfig = targetFramework switch + { + TestTargetFramework.Framework => """ + build_property.TargetFrameworkIdentifier = .NETFramework + build_property.TargetFrameworkVersion = v4.8 + """, + TestTargetFramework.Standard => """ + build_property.TargetFrameworkIdentifier = .NETStandard + build_property.TargetFrameworkVersion = v2.0 + """, + TestTargetFramework.Core => """ + build_property.TargetFrameworkIdentifier = .NETCoreApp + build_property.TargetFrameworkVersion = v3.1 + """, + TestTargetFramework.Net6 => """ + build_property.TargetFrameworkIdentifier = .NETCoreApp + build_property.TargetFrameworkVersion = v6.0 + """, + // Replicate the product case where we don't have these properties + // since we don't have a good mechanism to ship MSBuild files from dotnet/runtime + // in the SDK. + TestTargetFramework.Net => string.Empty, + _ => throw new System.Diagnostics.UnreachableException() + }; + return solution.AddAnalyzerConfigDocument( + DocumentId.CreateNewId(projectId), + "TargetFrameworkConfig.editorconfig", + SourceText.From(tfmEditorConfig, encoding: System.Text.Encoding.UTF8), + filePath: "/TargetFrameworkConfig.editorconfig"); + }; + } internal static Solution SetPreviewLanguageVersion(Solution solution, ProjectId projectId) { var project = solution.GetProject(projectId)!; From d8027c2b4769eee39cec3af337312ee61594e6cc Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 11 Apr 2023 14:39:19 -0700 Subject: [PATCH 05/17] Move over all tests other than CompileFails and the incremental testing to use the source generator test suite. --- .../Common/Verifiers/CSharpCodeFixVerifier.cs | 6 +- .../CSharpSourceGeneratorVerifier.cs | 54 ++- .../Common/Verifiers/CSharpVerifierHelper.cs | 9 +- .../AdditionalAttributesOnStub.cs | 113 +++--- .../AttributeForwarding.cs | 324 ++++++++++-------- .../Compiles.cs | 234 ++++++++----- .../Diagnostics.cs | 1 - 7 files changed, 424 insertions(+), 317 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs index c2c86f075c193..b63dffca7fa66 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpCodeFixVerifier.cs @@ -120,7 +120,6 @@ public Test() TestState.AdditionalReferences.Add(TestUtils.GetAncillaryReference()); SolutionTransforms.Add(CSharpVerifierHelper.GetAllDiagonsticsEnabledTransform(GetDiagnosticAnalyzers())); - SolutionTransforms.Add(CSharpVerifierHelper.SetPreviewLanguageVersion); } protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compilation compilation, ImmutableArray analyzers, AnalyzerOptions options, CancellationToken cancellationToken) @@ -149,6 +148,11 @@ protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compi return true; })); } + + protected override ParseOptions CreateParseOptions() + { + return new CSharpParseOptions(LanguageVersion.Preview, DocumentationMode.Diagnose); + } } } } 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 58a4546d9d174..abf7d23322754 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -40,8 +41,19 @@ public static DiagnosticResult DiagnosticWithArguments(DiagnosticDescriptor desc return Diagnostic(descriptor).WithMessage(string.Format(descriptor.MessageFormat.ToString(), arguments)).WithArguments(arguments); } - /// public static async Task VerifySourceGeneratorAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test(referenceAncillaryInterop: false) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + + public static async Task VerifySourceGeneratorWithAncillaryInteropAsync(string source, params DiagnosticResult[] expected) { var test = new Test(referenceAncillaryInterop: true) { @@ -53,6 +65,22 @@ public static async Task VerifySourceGeneratorAsync(string source, params Diagno await test.RunAsync(CancellationToken.None); } + public static async Task VerifySourceGeneratorAsync(string[] sources, params DiagnosticResult[] expected) + { + var test = new Test(referenceAncillaryInterop: true) + { + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + + foreach (var source in sources) + { + test.TestState.Sources.Add(source); + } + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + internal class Test : CSharpSourceGeneratorTest { public Test(TestTargetFramework targetFramework) @@ -86,7 +114,6 @@ public Test(bool referenceAncillaryInterop) } SolutionTransforms.Add(CSharpVerifierHelper.GetAllDiagonsticsEnabledTransform(GetDiagnosticAnalyzers())); - SolutionTransforms.Add(CSharpVerifierHelper.SetPreviewLanguageVersion); } protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compilation compilation, ImmutableArray analyzers, AnalyzerOptions options, CancellationToken cancellationToken) @@ -115,6 +142,29 @@ protected override CompilationWithAnalyzers CreateCompilationWithAnalyzers(Compi return true; })); } + + protected override ParseOptions CreateParseOptions() + { + return new CSharpParseOptions(LanguageVersion.Preview, DocumentationMode.Diagnose); + } + + protected async override Task<(Compilation compilation, ImmutableArray generatorDiagnostics)> GetProjectCompilationAsync(Project project, IVerifier verifier, CancellationToken cancellationToken) + { + var (compilation, diagnostics) = await base.GetProjectCompilationAsync(project, verifier, cancellationToken); + VerifyFinalCompilation(compilation); + return (compilation, diagnostics); + } + + /// + /// Verify any expected invariants on the final compilation after the source generators have been applied. + /// + /// The compilation. + /// + /// This function is useful for basic semantic testing of the generated code and can be used instead of verification testing of an exact match to the expected source output. + /// + protected virtual void VerifyFinalCompilation(Compilation compilation) + { + } } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs index 15a88f89a798e..8df1cbb573e90 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpVerifierHelper.cs @@ -80,18 +80,22 @@ internal static Func GetTargetFrameworkAnalyzerOp string tfmEditorConfig = targetFramework switch { TestTargetFramework.Framework => """ + is_global = true build_property.TargetFrameworkIdentifier = .NETFramework build_property.TargetFrameworkVersion = v4.8 """, TestTargetFramework.Standard => """ + is_global = true build_property.TargetFrameworkIdentifier = .NETStandard build_property.TargetFrameworkVersion = v2.0 """, TestTargetFramework.Core => """ + is_global = true build_property.TargetFrameworkIdentifier = .NETCoreApp build_property.TargetFrameworkVersion = v3.1 """, TestTargetFramework.Net6 => """ + is_global = true build_property.TargetFrameworkIdentifier = .NETCoreApp build_property.TargetFrameworkVersion = v6.0 """, @@ -108,10 +112,5 @@ internal static Func GetTargetFrameworkAnalyzerOp filePath: "/TargetFrameworkConfig.editorconfig"); }; } - internal static Solution SetPreviewLanguageVersion(Solution solution, ProjectId projectId) - { - var project = solution.GetProject(projectId)!; - return solution.WithProjectParseOptions(projectId, ((CSharpParseOptions)project.ParseOptions!).WithLanguageVersion(LanguageVersion.Preview)); - } } } 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 1c81253b5d166..08d7c0e1a74be 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AdditionalAttributesOnStub.cs @@ -2,14 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. 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; using System.Threading.Tasks; using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + namespace LibraryImportGenerator.UnitTests { public class AdditionalAttributesOnStub @@ -45,13 +47,7 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation comp = await TestUtils.CreateCompilation(source); - - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); - - ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; - IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); - Assert.Contains(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(SkipLocalsInitAttribute).FullName); + await VerifySourceGeneratorAsync(source, "C", "Method", typeof(SkipLocalsInitAttribute).FullName, attributeAdded: true, TestTargetFramework.Net); } [Fact] @@ -65,13 +61,7 @@ partial class C public static partial void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); - - ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; - IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); - Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(SkipLocalsInitAttribute).FullName); + await VerifySourceGeneratorAsync(source, "C", "Method", typeof(SkipLocalsInitAttribute).FullName, attributeAdded: false, TestTargetFramework.Net); } [Fact] @@ -105,13 +95,7 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation comp = await TestUtils.CreateCompilation(source); - - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); - - ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; - IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); - Assert.Contains(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName); + await VerifySourceGeneratorAsync(source, "C", "Method", typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName, attributeAdded: true, TestTargetFramework.Net); } [Fact] @@ -125,13 +109,7 @@ partial class C public static partial void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); - - ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; - IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); - Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName); + await VerifySourceGeneratorAsync(source, "C", "Method", typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName, attributeAdded: false, TestTargetFramework.Net); } public static IEnumerable GetDownlevelTargetFrameworks() @@ -158,20 +136,7 @@ partial class C public static partial bool Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source, targetFramework); - - 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"); - if (expectSkipLocalsInit) - { - Assert.Contains(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(SkipLocalsInitAttribute).FullName); - } - else - { - Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(SkipLocalsInitAttribute).FullName); - } + await VerifySourceGeneratorAsync(source, "C", "Method", typeof(SkipLocalsInitAttribute).FullName, attributeAdded: expectSkipLocalsInit, targetFramework); } [Fact] @@ -205,13 +170,7 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation comp = await TestUtils.CreateCompilation(source); - - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); - - ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; - IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); - Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(SkipLocalsInitAttribute).FullName); + await VerifySourceGeneratorAsync(source, "C", "Method", typeof(SkipLocalsInitAttribute).FullName, attributeAdded: false, TestTargetFramework.Net); } [Fact] @@ -245,13 +204,7 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation comp = await TestUtils.CreateCompilation(source); - - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); - - ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; - IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); - Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(SkipLocalsInitAttribute).FullName); + await VerifySourceGeneratorAsync(source, "C", "Method", typeof(SkipLocalsInitAttribute).FullName, attributeAdded: false, TestTargetFramework.Net); } [Fact] @@ -285,13 +238,49 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation comp = await TestUtils.CreateCompilation(source); + // Verify that we get no diagnostics from applying the attribute twice. + await VerifyCS.VerifySourceGeneratorAsync(source); + } - Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.LibraryImportGenerator()); + private static Task VerifySourceGeneratorAsync(string source, string typeName, string methodName, string? attributeName, bool attributeAdded, TestTargetFramework targetFramework) + { + AttributeAddedTest test = new(typeName, methodName, attributeName, attributeAdded, targetFramework) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + return test.RunAsync(); + } + + class AttributeAddedTest : VerifyCS.Test + { + private readonly string _typeName; + private readonly string _methodName; + private readonly string? _attributeName; + private readonly bool _expectSkipLocalsInit; - ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; - IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); - Assert.DoesNotContain(newComp.GetDiagnostics(), d => d.Id != "CS0579"); // No duplicate attribute error + public AttributeAddedTest(string typeName, string methodName, string? attributeName, bool expectSkipLocalsInitOnMethod, TestTargetFramework targetFramework) + : base(targetFramework) + { + _typeName = typeName; + _methodName = methodName; + _attributeName = attributeName; + _expectSkipLocalsInit = expectSkipLocalsInitOnMethod; + } + + protected override void VerifyFinalCompilation(Compilation compilation) + { + ITypeSymbol c = compilation.GetTypeByMetadataName(_typeName)!; + IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == _methodName); + if (_expectSkipLocalsInit) + { + Assert.Contains(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == _attributeName); + } + else + { + Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == _attributeName); + } + } } } } 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 2f055e1caceb6..1a5322bd85956 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AttributeForwarding.cs @@ -3,17 +3,16 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop; using Microsoft.Interop.UnitTests; using SourceGenerators.Tests; using System; -using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Runtime.InteropServices; -using System.Text; using System.Threading.Tasks; using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; namespace LibraryImportGenerator.UnitTests { @@ -53,19 +52,18 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation origComp = await TestUtils.CreateCompilation(source); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(newComp.GetDiagnostics()); - ITypeSymbol attributeType = newComp.GetTypeByMetadataName(attributeMetadataName)!; - - Assert.NotNull(attributeType); - - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + ITypeSymbol attributeType = newComp.GetTypeByMetadataName(attributeMetadataName)!; + Assert.NotNull(attributeType); - Assert.Contains( - targetMethod.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType)); + Assert.Contains( + targetMethod.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType)); + }); } [Fact] @@ -101,22 +99,21 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation origComp = await TestUtils.CreateCompilation(source); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(newComp.GetDiagnostics()); - - ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.UnmanagedCallConvAttribute")!; - - Assert.NotNull(attributeType); - - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); - Assert.Contains( - targetMethod.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) - && attr.NamedArguments.Length == 1 - && attr.NamedArguments[0].Key == "CallConvs" - && attr.NamedArguments[0].Value.Values.Length == 0); + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.UnmanagedCallConvAttribute")!; + Assert.NotNull(attributeType); + + Assert.Contains( + targetMethod.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) + && attr.NamedArguments.Length == 1 + && attr.NamedArguments[0].Key == "CallConvs" + && attr.NamedArguments[0].Value.Values.Length == 0); + }); } [Fact] @@ -151,26 +148,26 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation origComp = await TestUtils.CreateCompilation(source); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(newComp.GetDiagnostics()); - - ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.UnmanagedCallConvAttribute")!; - ITypeSymbol callConvType = newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvStdcall")!; - - Assert.NotNull(attributeType); - - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); - - Assert.Contains( - targetMethod.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) - && attr.NamedArguments.Length == 1 - && attr.NamedArguments[0].Key == "CallConvs" - && attr.NamedArguments[0].Value.Values.Length == 1 - && SymbolEqualityComparer.Default.Equals( - (INamedTypeSymbol?)attr.NamedArguments[0].Value.Values[0].Value!, - callConvType)); + + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.UnmanagedCallConvAttribute")!; + ITypeSymbol callConvType = newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvStdcall")!; + + Assert.NotNull(attributeType); + + Assert.Contains( + targetMethod.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) + && attr.NamedArguments.Length == 1 + && attr.NamedArguments[0].Key == "CallConvs" + && attr.NamedArguments[0].Value.Values.Length == 1 + && SymbolEqualityComparer.Default.Equals( + (INamedTypeSymbol?)attr.NamedArguments[0].Value.Values[0].Value!, + callConvType)); + }); } [Fact] @@ -205,30 +202,30 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation origComp = await TestUtils.CreateCompilation(source); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(newComp.GetDiagnostics()); - - ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.UnmanagedCallConvAttribute")!; - ITypeSymbol callConvType = newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvStdcall")!; - ITypeSymbol callConvType2 = newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition")!; - - Assert.NotNull(attributeType); - - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); - - Assert.Contains( - targetMethod.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) - && attr.NamedArguments.Length == 1 - && attr.NamedArguments[0].Key == "CallConvs" - && attr.NamedArguments[0].Value.Values.Length == 2 - && SymbolEqualityComparer.Default.Equals( - (INamedTypeSymbol?)attr.NamedArguments[0].Value.Values[0].Value!, - callConvType) - && SymbolEqualityComparer.Default.Equals( - (INamedTypeSymbol?)attr.NamedArguments[0].Value.Values[1].Value!, - callConvType2)); + + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.UnmanagedCallConvAttribute")!; + ITypeSymbol callConvType = newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvStdcall")!; + ITypeSymbol callConvType2 = newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition")!; + + Assert.NotNull(attributeType); + + Assert.Contains( + targetMethod.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) + && attr.NamedArguments.Length == 1 + && attr.NamedArguments[0].Key == "CallConvs" + && attr.NamedArguments[0].Value.Values.Length == 2 + && SymbolEqualityComparer.Default.Equals( + (INamedTypeSymbol?)attr.NamedArguments[0].Value.Values[0].Value!, + callConvType) + && SymbolEqualityComparer.Default.Equals( + (INamedTypeSymbol?)attr.NamedArguments[0].Value.Values[1].Value!, + callConvType2)); + }); } [Fact] @@ -263,23 +260,23 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation origComp = await TestUtils.CreateCompilation(source); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(newComp.GetDiagnostics()); - - ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute")!; - Assert.NotNull(attributeType); + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + ITypeSymbol attributeType = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute")!; - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); + Assert.NotNull(attributeType); - DllImportSearchPath expected = DllImportSearchPath.System32 | DllImportSearchPath.UserDirectories; + DllImportSearchPath expected = DllImportSearchPath.System32 | DllImportSearchPath.UserDirectories; - Assert.Contains( - targetMethod.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) - && attr.ConstructorArguments.Length == 1 - && expected == (DllImportSearchPath)attr.ConstructorArguments[0].Value!); + Assert.Contains( + targetMethod.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType) + && attr.ConstructorArguments.Length == 1 + && expected == (DllImportSearchPath)attr.ConstructorArguments[0].Value!); + }); } [Fact] @@ -318,20 +315,20 @@ static class Marshaller public static S ConvertToManaged(Native n) => default; } """; - Compilation origComp = await TestUtils.CreateCompilation(source); - Compilation newComp = TestUtils.RunGenerators(origComp, out _, new Microsoft.Interop.LibraryImportGenerator()); - - Assert.Empty(newComp.GetDiagnostics()); - ITypeSymbol attributeType = newComp.GetTypeByMetadataName("OtherAttribute")!; + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + ITypeSymbol attributeType = newComp.GetTypeByMetadataName("OtherAttribute")!; - Assert.NotNull(attributeType); + Assert.NotNull(attributeType); - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); - Assert.DoesNotContain( - targetMethod.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType)); + Assert.DoesNotContain( + targetMethod.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType)); + }); } [Fact] @@ -347,35 +344,33 @@ partial class C { [LibraryImportAttribute("DoesNotExist")] [return: MarshalAs(UnmanagedType.Bool)] - public static partial bool Method1([In, Out] int a); + public static partial bool Method1([In, Out] int {|SYSLIB1051:a|}); } """ + CodeSnippets.LibraryImportAttributeDeclaration; - Compilation origComp = await TestUtils.CreateCompilation(source, TestTargetFramework.Standard); - Compilation newComp = TestUtils.RunGenerators( - origComp, - new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(TestTargetFramework.Standard)), - out _, - new Microsoft.Interop.LibraryImportGenerator()); - - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); - - INamedTypeSymbol marshalAsAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)!; - INamedTypeSymbol inAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_InAttribute)!; - INamedTypeSymbol outAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_OutAttribute)!; - Assert.Collection(targetMethod.Parameters, - param => Assert.Collection(param.GetAttributes(), - attr => - { - Assert.Equal(inAttribute, attr.AttributeClass, SymbolEqualityComparer.Default); - Assert.Empty(attr.ConstructorArguments); - Assert.Empty(attr.NamedArguments); - }, - attr => - { - Assert.Equal(outAttribute, attr.AttributeClass, SymbolEqualityComparer.Default); - Assert.Empty(attr.ConstructorArguments); - Assert.Empty(attr.NamedArguments); - })); + + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + INamedTypeSymbol marshalAsAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)!; + INamedTypeSymbol inAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_InAttribute)!; + INamedTypeSymbol outAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_OutAttribute)!; + Assert.Collection(targetMethod.Parameters, + param => Assert.Collection(param.GetAttributes(), + attr => + { + Assert.Equal(inAttribute, attr.AttributeClass, SymbolEqualityComparer.Default); + Assert.Empty(attr.ConstructorArguments); + Assert.Empty(attr.NamedArguments); + }, + attr => + { + Assert.Equal(outAttribute, attr.AttributeClass, SymbolEqualityComparer.Default); + Assert.Empty(attr.ConstructorArguments); + Assert.Empty(attr.NamedArguments); + })); + }, + TestTargetFramework.Standard); } [Fact] @@ -392,38 +387,63 @@ partial class C public static partial bool Method1([MarshalAs(UnmanagedType.I2)] int a); } """ + CodeSnippets.LibraryImportAttributeDeclaration; - Compilation origComp = await TestUtils.CreateCompilation(source, TestTargetFramework.Standard); - Compilation newComp = TestUtils.RunGenerators( - origComp, - new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(TestTargetFramework.Standard)), - out _, - new Microsoft.Interop.LibraryImportGenerator()); - - IMethodSymbol targetMethod = GetGeneratedPInvokeTargetFromCompilation(newComp); - - INamedTypeSymbol marshalAsAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)!; - Assert.Collection(targetMethod.Parameters, - param => Assert.Collection(param.GetAttributes(), - attr => - { - Assert.Equal(marshalAsAttribute, attr.AttributeClass, SymbolEqualityComparer.Default); - Assert.Equal(UnmanagedType.I2, (UnmanagedType)attr.ConstructorArguments[0].Value!); - Assert.Empty(attr.NamedArguments); - })); + + await VerifySourceGeneratorAsync( + source, + (targetMethod, newComp) => + { + INamedTypeSymbol marshalAsAttribute = newComp.GetTypeByMetadataName(TypeNames.System_Runtime_InteropServices_MarshalAsAttribute)!; + Assert.Collection(targetMethod.Parameters, + param => Assert.Collection(param.GetAttributes(), + attr => + { + Assert.Equal(marshalAsAttribute, attr.AttributeClass, SymbolEqualityComparer.Default); + Assert.Equal(UnmanagedType.I2, (UnmanagedType)attr.ConstructorArguments[0].Value!); + Assert.Empty(attr.NamedArguments); + })); + }, + TestTargetFramework.Standard); + } + + private static Task VerifySourceGeneratorAsync(string source, Action targetPInvokeAssertion, TestTargetFramework targetFramework = TestTargetFramework.Net) + { + var test = new GeneratedTargetPInvokeTest(targetPInvokeAssertion, targetFramework) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + + return test.RunAsync(); } - private static IMethodSymbol GetGeneratedPInvokeTargetFromCompilation(Compilation newComp) + class GeneratedTargetPInvokeTest : VerifyCS.Test { - // The last syntax tree is the generated code - SyntaxTree generatedCode = newComp.SyntaxTrees.Last(); - SemanticModel model = newComp.GetSemanticModel(generatedCode); - - var localFunctions = generatedCode.GetRoot() - .DescendantNodes().OfType() - .ToList(); - LocalFunctionStatementSyntax innerDllImport = Assert.Single(localFunctions); - IMethodSymbol targetMethod = (IMethodSymbol)model.GetDeclaredSymbol(innerDllImport)!; - return targetMethod; + private readonly Action _targetPInvokeAssertion; + + public GeneratedTargetPInvokeTest(Action targetPInvokeAssertion, TestTargetFramework targetFramework) + :base(targetFramework) + { + _targetPInvokeAssertion = targetPInvokeAssertion; + } + + private static IMethodSymbol GetGeneratedPInvokeTargetFromCompilation(Compilation compilation) + { + // The last syntax tree is the generated code + SyntaxTree generatedCode = compilation.SyntaxTrees.Last(); + SemanticModel model = compilation.GetSemanticModel(generatedCode); + + var localFunctions = generatedCode.GetRoot() + .DescendantNodes().OfType() + .ToList(); + LocalFunctionStatementSyntax innerDllImport = Assert.Single(localFunctions); + IMethodSymbol targetMethod = (IMethodSymbol)model.GetDeclaredSymbol(innerDllImport)!; + return targetMethod; + } + + protected override void VerifyFinalCompilation(Compilation compilation) + { + _targetPInvokeAssertion(GetGeneratedPInvokeTargetFromCompilation(compilation), compilation); + } } } } 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 f92f137f3911e..4b74eda196aba 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -14,6 +14,13 @@ using Xunit; using SourceGenerators.Tests; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; +using Microsoft.CodeAnalysis.Testing; +using System.Collections.Immutable; +using System.Threading; +using Microsoft.CodeAnalysis.Text; +using System.Text; + namespace LibraryImportGenerator.UnitTests { public class Compiles @@ -418,13 +425,8 @@ public static IEnumerable CustomCollections() public async Task ValidateSnippets(string id, string source) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(generatorDiags); - TestUtils.AssertPostSourceGeneratorCompilation(newComp); + await VerifyCS.VerifySourceGeneratorAsync(source); } public static IEnumerable CodeSnippetsToCompileWithPreprocessorSymbols() @@ -443,23 +445,37 @@ public static IEnumerable CodeSnippetsToCompileWithPreprocessorSymbols public async Task ValidateSnippetsWithPreprocessorDefinitions(string id, string source, IEnumerable preprocessorSymbols) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source, preprocessorSymbols: preprocessorSymbols); - TestUtils.AssertPreSourceGeneratorCompilation(comp); + var test = new PreprocessorTest(preprocessorSymbols) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + + await test.RunAsync(); + } + + private class PreprocessorTest : VerifyCS.Test + { + private readonly IEnumerable _preprocessorSymbols; - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(generatorDiags); + public PreprocessorTest(IEnumerable preprocessorSymbols) + :base(referenceAncillaryInterop: false) + { + _preprocessorSymbols = preprocessorSymbols; + } - TestUtils.AssertPostSourceGeneratorCompilation(newComp); + protected override ParseOptions CreateParseOptions() + => ((CSharpParseOptions)base.CreateParseOptions()).WithPreprocessorSymbols(_preprocessorSymbols); } public static IEnumerable CodeSnippetsToValidateFallbackForwarder() { - yield return new object[] { ID(), CodeSnippets.UserDefinedEntryPoint, TestTargetFramework.Net, true }; + //yield return new object[] { ID(), CodeSnippets.UserDefinedEntryPoint, TestTargetFramework.Net, true }; // Confirm that all unsupported target frameworks can be generated. { string code = CodeSnippets.BasicParametersAndModifiers(CodeSnippets.LibraryImportAttributeDeclaration); - yield return new object[] { ID(), code, TestTargetFramework.Net6, false }; + //yield return new object[] { ID(), code, TestTargetFramework.Net6, false }; yield return new object[] { ID(), code, TestTargetFramework.Core, false }; yield return new object[] { ID(), code, TestTargetFramework.Standard, false }; yield return new object[] { ID(), code, TestTargetFramework.Framework, false }; @@ -499,31 +515,38 @@ public static IEnumerable CodeSnippetsToValidateFallbackForwarder() public async Task ValidateSnippetsFallbackForwarder(string id, string source, TestTargetFramework targetFramework, bool expectFallbackForwarder) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source, targetFramework); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators( - comp, - new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(targetFramework)), - out var generatorDiags, - new Microsoft.Interop.LibraryImportGenerator()); + var test = new FallbackForwarderTest(targetFramework, expectFallbackForwarder) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; - Assert.Empty(generatorDiags); + await test.RunAsync(); + } - TestUtils.AssertPostSourceGeneratorCompilation(newComp); + class FallbackForwarderTest : VerifyCS.Test + { + private readonly bool _expectFallbackForwarder; - // Verify that the forwarder generates the method as a DllImport. - SyntaxTree generatedCode = newComp.SyntaxTrees.Last(); - SemanticModel model = newComp.GetSemanticModel(generatedCode); - var methods = generatedCode.GetRoot() - .DescendantNodes().OfType() - .ToList(); - MethodDeclarationSyntax generatedMethod = Assert.Single(methods); + public FallbackForwarderTest(TestTargetFramework targetFramework, bool expectFallbackForwarder) + :base(targetFramework) + { + _expectFallbackForwarder = expectFallbackForwarder; + } + protected override void VerifyFinalCompilation(Compilation compilation) + { + SyntaxTree generatedCode = compilation.SyntaxTrees.Last(); + SemanticModel model = compilation.GetSemanticModel(generatedCode); + var methods = generatedCode.GetRoot() + .DescendantNodes().OfType() + .ToList(); + MethodDeclarationSyntax generatedMethod = Assert.Single(methods); - IMethodSymbol method = model.GetDeclaredSymbol(generatedMethod)!; + IMethodSymbol method = model.GetDeclaredSymbol(generatedMethod)!; - // If we expect fallback forwarder, then the DllImportData will not be null. - Assert.Equal(expectFallbackForwarder, method.GetDllImportData() is not null); + // If we expect fallback forwarder, then the DllImportData will not be null. + Assert.Equal(_expectFallbackForwarder, method.GetDllImportData() is not null); + } } public static IEnumerable FullyBlittableSnippetsToCompile() @@ -537,26 +560,32 @@ public static IEnumerable FullyBlittableSnippetsToCompile() public async Task ValidateSnippetsWithBlittableAutoForwarding(string id, string source) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators( - comp, - out var generatorDiags, - new Microsoft.Interop.LibraryImportGenerator()); + var test = new BlittableAutoForwarderTest() + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; - Assert.Empty(generatorDiags); + await test.RunAsync(); + } - TestUtils.AssertPostSourceGeneratorCompilation(newComp); + class BlittableAutoForwarderTest : VerifyCS.Test + { + public BlittableAutoForwarderTest() + :base(referenceAncillaryInterop: false) + { + } - // Verify that the forwarder generates the method as a DllImport. - SyntaxTree generatedCode = newComp.SyntaxTrees.Last(); - SemanticModel model = newComp.GetSemanticModel(generatedCode); - var methods = generatedCode.GetRoot() - .DescendantNodes().OfType() - .ToList(); + protected override void VerifyFinalCompilation(Compilation compilation) + { + SyntaxTree generatedCode = compilation.SyntaxTrees.Last(); + SemanticModel model = compilation.GetSemanticModel(generatedCode); + var methods = generatedCode.GetRoot() + .DescendantNodes().OfType() + .ToList(); - Assert.All(methods, method => Assert.NotNull(model.GetDeclaredSymbol(method)!.GetDllImportData())); + Assert.All(methods, method => Assert.NotNull(model.GetDeclaredSymbol(method)!.GetDllImportData())); + } } public static IEnumerable SnippetsWithBlittableTypesButNonBlittableDataToCompile() @@ -571,29 +600,34 @@ public static IEnumerable SnippetsWithBlittableTypesButNonBlittableDat public async Task ValidateSnippetsWithBlittableTypesButNonBlittableMetadataDoNotAutoForward(string id, string source) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators( - comp, - out var generatorDiags, - new Microsoft.Interop.LibraryImportGenerator()); - - Assert.Empty(generatorDiags); + var test = new NonBlittableNoAutoForwardTest() + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; - TestUtils.AssertPostSourceGeneratorCompilation(newComp); + await test.RunAsync(); + } - // Verify that the generator generates stubs with inner DllImports for all methods. - SyntaxTree generatedCode = newComp.SyntaxTrees.Last(); - SemanticModel model = newComp.GetSemanticModel(generatedCode); - int numStubMethods = generatedCode.GetRoot() - .DescendantNodes().OfType() - .Count(); - int numInnerDllImports = generatedCode.GetRoot() - .DescendantNodes().OfType() - .Count(); + class NonBlittableNoAutoForwardTest : VerifyCS.Test + { + public NonBlittableNoAutoForwardTest() + : base(referenceAncillaryInterop: false) + { + } - Assert.Equal(numStubMethods, numInnerDllImports); + protected override void VerifyFinalCompilation(Compilation compilation) + { + SyntaxTree generatedCode = compilation.SyntaxTrees.Last(); + SemanticModel model = compilation.GetSemanticModel(generatedCode); + int numStubMethods = generatedCode.GetRoot() + .DescendantNodes().OfType() + .Count(); + int numInnerDllImports = generatedCode.GetRoot() + .DescendantNodes().OfType() + .Count(); + Assert.Equal(numStubMethods, numInnerDllImports); + } } public static IEnumerable CodeSnippetsToCompileWithMarshalType() @@ -610,18 +644,21 @@ public static IEnumerable CodeSnippetsToCompileWithMarshalType() public async Task ValidateSnippetsWithMarshalType(string id, string source) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators( - comp, - new LibraryImportGeneratorOptionsProvider(TestTargetFramework.Net, useMarshalType: true, generateForwarders: false), - out var generatorDiags, - new Microsoft.Interop.LibraryImportGenerator()); - - Assert.Empty(generatorDiags); - - TestUtils.AssertPostSourceGeneratorCompilation(newComp, "CS0117"); + var test = new VerifyCS.Test(referenceAncillaryInterop: true) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + test.SolutionTransforms.Add((solution, projectId) => + solution.AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId), + "UseMarshalType.editorconfig", + SourceText.From(""" + is_global = true + build_property.LibraryImportGenerator_UseMarshalType = true + """, + Encoding.UTF8), + filePath: "/UseMarshalType.editorconfig")); + await test.RunAsync(); } public static IEnumerable CodeSnippetsToCompileMultipleSources() @@ -636,13 +673,7 @@ public static IEnumerable CodeSnippetsToCompileMultipleSources() public async Task ValidateSnippetsWithMultipleSources(string id, string[] sources) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(sources); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(generatorDiags); - - TestUtils.AssertPostSourceGeneratorCompilation(newComp); + await VerifyCS.VerifySourceGeneratorAsync(sources); } public static IEnumerable CodeSnippetsToVerifyNoTreesProduced() @@ -661,14 +692,29 @@ public class Basic { } public async Task ValidateNoGeneratedOuptutForNoImport(string id, string source, TestTargetFramework framework) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source, framework, allowUnsafe: false); - TestUtils.AssertPreSourceGeneratorCompilation(comp); + var test = new NoChangeTest(framework) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + + await test.RunAsync(); + } - var newComp = TestUtils.RunGenerators(comp, new GlobalOptionsOnlyProvider(new TargetFrameworkConfigOptions(framework)), out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - Assert.Empty(generatorDiags); + class NoChangeTest : VerifyCS.Test + { + public NoChangeTest(TestTargetFramework framework) + :base(framework) + { + } - // Assert we didn't generate any syntax trees, even empty ones - Assert.Same(comp, newComp); + protected async override Task<(Compilation compilation, ImmutableArray generatorDiagnostics)> GetProjectCompilationAsync(Project project, IVerifier verifier, CancellationToken cancellationToken) + { + var originalCompilation = await project.GetCompilationAsync(cancellationToken); + var (newCompilation, diagnostics) = await base.GetProjectCompilationAsync(project, verifier, cancellationToken); + Assert.Same(originalCompilation, newCompilation); + return (newCompilation, diagnostics); + } } } } 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 de4081cd5aaba..030ffba39431d 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Diagnostics.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop; using Microsoft.Interop.UnitTests; -using SourceGenerators.Tests; using Xunit; using StringMarshalling = Microsoft.Interop.StringMarshalling; From c3418f728356279fc0c74c9bf0d61611798e9c6d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 11 Apr 2023 14:39:43 -0700 Subject: [PATCH 06/17] Add the source generator test package to ComInterfaceGenerator.Unit.Tests.csproj --- .../ComInterfaceGenerator.Unit.Tests.csproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 64e7dd10a070d..6766f8e39fb05 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 @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent) @@ -27,6 +27,8 @@ Link="Verifiers\CSharpAnalyzerVerifier.cs"/> + @@ -35,6 +37,7 @@ + From 2627e8de30eb275d65e41b26e04513dfdb5d6b6d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 12 Apr 2023 15:24:29 -0700 Subject: [PATCH 07/17] Move over the small CompileFails theories. --- .../CodeSnippets.cs | 39 ++++--- .../CompileFails.cs | 100 ++++++++++++------ 2 files changed, 94 insertions(+), 45 deletions(-) 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 1523ac5b4c1c5..7655d8a71be5a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs @@ -72,7 +72,7 @@ public LibraryImportAttribute(string a) { } /// public static readonly string TrivialClassDeclarations = """ using System.Runtime.InteropServices; - partial class Basic + partial class {|#0:Basic|} { [LibraryImportAttribute("DoesNotExist")] public static partial void Method1(); @@ -675,6 +675,21 @@ public static partial void Method( /// /// Declaration with parameters with MarshalAs. /// + //public static string MarshalUsingParametersAndModifiers(string typeName, string nativeTypeName, string preDeclaration = "") => $$""" + // using System.Runtime.InteropServices; + // using System.Runtime.InteropServices.Marshalling; + // {{preDeclaration}} + // partial class Test + // { + // [LibraryImport("DoesNotExist")] + // [return: MarshalUsing(typeof({{nativeTypeName}}))] + // public static partial {{typeName}} Method( + // [MarshalUsing(typeof({{nativeTypeName}}))] {{typeName}} p, + // [MarshalUsing(typeof({{nativeTypeName}}))] in {{typeName}} pIn, + // [MarshalUsing(typeof({{nativeTypeName}}))] ref {{typeName}} pRef, + // [MarshalUsing(typeof({{nativeTypeName}}))] out {{typeName}} pOut); + // } + // """; public static string MarshalUsingParametersAndModifiers(string typeName, string nativeTypeName, string preDeclaration = "") => $$""" using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; @@ -683,11 +698,11 @@ partial class Test { [LibraryImport("DoesNotExist")] [return: MarshalUsing(typeof({{nativeTypeName}}))] - public static partial {{typeName}} Method( - [MarshalUsing(typeof({{nativeTypeName}}))] {{typeName}} p, - [MarshalUsing(typeof({{nativeTypeName}}))] in {{typeName}} pIn, - [MarshalUsing(typeof({{nativeTypeName}}))] ref {{typeName}} pRef, - [MarshalUsing(typeof({{nativeTypeName}}))] out {{typeName}} pOut); + public static partial {{typeName}} {|#0:Method|}( + [MarshalUsing(typeof({{nativeTypeName}}))] {{typeName}} {|#1:p|}, + [MarshalUsing(typeof({{nativeTypeName}}))] in {{typeName}} {|#2:pIn|}, + [MarshalUsing(typeof({{nativeTypeName}}))] ref {{typeName}} {|#3:pRef|}, + [MarshalUsing(typeof({{nativeTypeName}}))] out {{typeName}} {|#4:pOut|}); } """; public static string BasicParameterWithByRefModifier(string byRefKind, string typeName, string preDeclaration = "") => $$""" @@ -832,20 +847,20 @@ public static string MaybeBlittableGenericTypeParametersAndModifiers() => public static string RecursiveImplicitlyBlittableStruct => BasicParametersAndModifiers("RecursiveStruct", DisableRuntimeMarshalling) + """ struct RecursiveStruct { - RecursiveStruct s; + RecursiveStruct {|CS0523:s|}; int i; } """; public static string MutuallyRecursiveImplicitlyBlittableStruct => BasicParametersAndModifiers("RecursiveStruct1", DisableRuntimeMarshalling) + """ struct RecursiveStruct1 { - RecursiveStruct2 s; + RecursiveStruct2 {|CS0523:s|}; int i; } struct RecursiveStruct2 { - RecursiveStruct1 s; + RecursiveStruct1 {|CS0523:s|}; int i; } """; @@ -1206,7 +1221,7 @@ partial struct Basic partial struct Basic { - [LibraryImport("DoesNotExist", SetLa)] + [{|CS1729:LibraryImport("DoesNotExist", {|CS0103:SetLa|})|}] public static partial void Method(); } """; @@ -1215,7 +1230,7 @@ partial struct Basic partial struct Basic { - [LibraryImport(DoesNotExist)] + [LibraryImport({|CS0103:DoesNotExist|})] public static partial void Method(); } """; @@ -1224,7 +1239,7 @@ partial struct Basic partial struct Basic { - [LibraryImport("DoesNotExist", SetLastError = "Foo")] + [LibraryImport("DoesNotExist", SetLastError = {|CS0029:"Foo"|})] public static partial void Method(); } """; 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 613588fb6b217..9782cf2bf5442 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs @@ -11,9 +11,16 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.Interop; using Microsoft.Interop.UnitTests; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Xunit; +using StringMarshalling = System.Runtime.InteropServices.StringMarshalling; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + namespace LibraryImportGenerator.UnitTests { public class CompileFails @@ -161,72 +168,99 @@ public async Task ValidateSnippets(string id, string source, int expectedGenerat public static IEnumerable CodeSnippetsToCompile_InvalidCode() { - yield return new object[] { ID(), CodeSnippets.RecursiveImplicitlyBlittableStruct, 0, 1 }; - yield return new object[] { ID(), CodeSnippets.MutuallyRecursiveImplicitlyBlittableStruct, 0, 2 }; - yield return new object[] { ID(), CodeSnippets.PartialPropertyName, 0, 2 }; - yield return new object[] { ID(), CodeSnippets.InvalidConstantForModuleName, 0, 1 }; - yield return new object[] { ID(), CodeSnippets.IncorrectAttributeFieldType, 0, 1 }; + yield return new[] { ID(), CodeSnippets.RecursiveImplicitlyBlittableStruct }; + yield return new[] { ID(), CodeSnippets.MutuallyRecursiveImplicitlyBlittableStruct }; + yield return new[] { ID(), CodeSnippets.PartialPropertyName }; + yield return new[] { ID(), CodeSnippets.InvalidConstantForModuleName }; + yield return new[] { ID(), CodeSnippets.IncorrectAttributeFieldType }; } [Theory] [MemberData(nameof(CodeSnippetsToCompile_InvalidCode))] - public async Task ValidateSnippets_InvalidCodeGracefulFailure(string id, string source, int expectedGeneratorErrors, int expectedCompilerErrors) + public async Task ValidateSnippets_InvalidCodeGracefulFailure(string id, string source) { TestUtils.Use(id); - // Do not validate that the compilation has no errors that the generator will not fix. - Compilation comp = await TestUtils.CreateCompilation(source); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - - // Verify the compilation failed with errors. - int generatorErrors = generatorDiags.Count(d => d.Severity == DiagnosticSeverity.Error); - Assert.Equal(expectedGeneratorErrors, generatorErrors); - - int compilerErrors = newComp.GetDiagnostics().Count(d => d.Severity == DiagnosticSeverity.Error); - Assert.Equal(expectedCompilerErrors, compilerErrors); + // Each snippet will contain the expected diagnostic codes in their expected locations for the compile errors. + // We expect there to be no generator diagnostics or failures. + await VerifyCS.VerifySourceGeneratorAsync(source); } [Fact] public async Task ValidateDisableRuntimeMarshallingForBlittabilityCheckFromAssemblyReference() { + // Emit the referenced assembly to a stream so we reference it through a metadata reference. + // Our check for strict blittability doesn't work correctly when using source compilation references. + // (There are sometimes false-positives.) + // This causes any diagnostics that depend on strict blittability being correctly calculated to + // not show up in the IDE experience. However, since they correctly show up when doing builds, + // either by running the Build command in the IDE or a command line build, we aren't allowing invalid code. + // This test validates the Build-like experience. In the future, we should update this test to validate the + // IDE-like experience once we fix that case + // (If the IDE experience works, then the command-line experience will also work.) string assemblySource = $$""" - using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; {{CodeSnippets.ValidateDisableRuntimeMarshalling.NonBlittableUserDefinedTypeWithNativeType}} """; Compilation assemblyComp = await TestUtils.CreateCompilation(assemblySource); - TestUtils.AssertPreSourceGeneratorCompilation(assemblyComp); + Assert.Empty(assemblyComp.GetDiagnostics()); var ms = new MemoryStream(); Assert.True(assemblyComp.Emit(ms).Success); string testSource = CodeSnippets.ValidateDisableRuntimeMarshalling.TypeUsage(string.Empty); - Compilation testComp = await TestUtils.CreateCompilation(testSource, refs: new[] { MetadataReference.CreateFromImage(ms.ToArray()) }); - TestUtils.AssertPreSourceGeneratorCompilation(testComp); + VerifyCS.Test test = new(referenceAncillaryInterop: false) + { + TestCode = testSource, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; - var newComp = TestUtils.RunGenerators(testComp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromImage(ms.ToArray())); // The errors should indicate the DisableRuntimeMarshalling is required. - Assert.True(generatorDiags.All(d => d.Id == "SYSLIB1051")); - - TestUtils.AssertPostSourceGeneratorCompilation(newComp); + test.ExpectedDiagnostics.Add( + 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.", "Method")); + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "p")); + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pIn")); + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pRef")); + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pOut")); + + await test.RunAsync(); } [Fact] public async Task ValidateRequireAllowUnsafeBlocksDiagnostic() { - string source = CodeSnippets.TrivialClassDeclarations; - Compilation comp = await TestUtils.CreateCompilation(new[] { source }, allowUnsafe: false); - TestUtils.AssertPreSourceGeneratorCompilation(comp); + var test = new AllowUnsafeBlocksTest() + { + TestCode = CodeSnippets.TrivialClassDeclarations, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); + test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic("SYSLIB1062")); + test.ExpectedDiagnostics.Add(DiagnosticResult.CompilerError("CS0227").WithLocation(0)); - // The errors should indicate the AllowUnsafeBlocks is required. - Assert.True(generatorDiags.All(d => d.Id == "SYSLIB1062")); + await test.RunAsync(); + } + + class AllowUnsafeBlocksTest : VerifyCS.Test + { + public AllowUnsafeBlocksTest() + :base(referenceAncillaryInterop: false) + { + } - // There should only be one SYSLIB1062, even if there are multiple LibraryImportAttribute uses. - Assert.Equal(1, generatorDiags.Count()); + protected override CompilationOptions CreateCompilationOptions() => ((CSharpCompilationOptions)base.CreateCompilationOptions()).WithAllowUnsafe(false); } } } From 1055a35253ef51621763cea9bccf5aabd2ea5d00 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 12 Apr 2023 15:55:21 -0700 Subject: [PATCH 08/17] Add issue reference. --- .../tests/LibraryImportGenerator.UnitTests/CompileFails.cs | 1 + 1 file changed, 1 insertion(+) 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 9782cf2bf5442..ba39727cbfa60 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs @@ -197,6 +197,7 @@ public async Task ValidateDisableRuntimeMarshallingForBlittabilityCheckFromAssem // This test validates the Build-like experience. In the future, we should update this test to validate the // IDE-like experience once we fix that case // (If the IDE experience works, then the command-line experience will also work.) + // This bug is tracked in https://github.com/dotnet/runtime/issues/84739. string assemblySource = $$""" using System.Runtime.InteropServices.Marshalling; {{CodeSnippets.ValidateDisableRuntimeMarshalling.NonBlittableUserDefinedTypeWithNativeType}} From 612432cb3f170150567ffe8722baa14cf74779d8 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 14 Apr 2023 15:46:02 -0700 Subject: [PATCH 09/17] Move ComipleFails tests to the new Diagnostics test setup. --- ...CustomCollectionMarshallingCodeSnippets.cs | 2 +- .../CustomStructMarshallingCodeSnippets.cs | 8 +- .../CodeSnippets.cs | 142 +-- .../CompileFails.cs | 846 ++++++++++++++++-- 4 files changed, 829 insertions(+), 169 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/CustomCollectionMarshallingCodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/CustomCollectionMarshallingCodeSnippets.cs index 4144748d319fa..f25a50341e9d0 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/CustomCollectionMarshallingCodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/CustomCollectionMarshallingCodeSnippets.cs @@ -278,7 +278,7 @@ public string NestedMarshallerParametersAndModifiers(string elementType) => _pro public string GenericCollectionMarshallingArityMismatch => _provider.BasicParameterByValue("TestCollection", DisableRuntimeMarshalling) + """ - [NativeMarshalling(typeof(Marshaller<,,>))] + [{|#10:NativeMarshalling(typeof(Marshaller<,,>))|}] class TestCollection {} [CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,,>))] diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/CustomStructMarshallingCodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/CustomStructMarshallingCodeSnippets.cs index b3ea19245914e..9b77d5f331153 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/CustomStructMarshallingCodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/CustomStructMarshallingCodeSnippets.cs @@ -18,7 +18,7 @@ public CustomStructMarshallingCodeSnippets(ICustomMarshallingSignatureTestProvid private static readonly string UsingSystemRuntimeInteropServicesMarshalling = "using System.Runtime.InteropServices.Marshalling;"; public static string NonBlittableUserDefinedType(bool defineNativeMarshalling = true) => $$""" - {{(defineNativeMarshalling ? "[NativeMarshalling(typeof(Marshaller))]" : string.Empty)}} + {{(defineNativeMarshalling ? "[{|#10:NativeMarshalling(typeof(Marshaller))|}]" : string.Empty)}} public struct S { #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value @@ -240,9 +240,9 @@ public struct Native { } + NonBlittableUserDefinedType() + Ref; - public string StackallocOnlyRefParameter => _provider.BasicParameterWithByRefModifier("ref", "S") - + NonBlittableUserDefinedType() - + InOutBuffer; + public string StackallocOnlyRefParameter => _provider.BasicParameterWithByRefModifier("ref", "S") + + NonBlittableUserDefinedType() + + InOutBuffer; public string OptionalStackallocParametersAndModifiers => _provider.BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) + NonBlittableUserDefinedType() 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 7655d8a71be5a..0eb9830693431 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs @@ -296,7 +296,7 @@ partial class Test using System.Runtime.InteropServices; partial class Test { - [LCIDConversion(0)] + [{|#0:LCIDConversion(0)|}] [LibraryImport("DoesNotExist")] public static partial void Method(); } @@ -335,12 +335,12 @@ public object MarshalNativeToManaged(IntPtr pNativeData) partial class Test { [LibraryImport("DoesNotExist")] - [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NS.MyCustomMarshaler), MarshalCookie="COOKIE1")] - public static partial bool Method1([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NS.MyCustomMarshaler), MarshalCookie="COOKIE2")]bool t); + [return: {|#0:MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NS.MyCustomMarshaler), MarshalCookie="COOKIE1")|}] + public static partial bool {|#1:Method1|}([{|#2:MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NS.MyCustomMarshaler), MarshalCookie="COOKIE2")|}]bool {|#3:t|}); [LibraryImport("DoesNotExist")] - [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "NS.MyCustomMarshaler", MarshalCookie="COOKIE3")] - public static partial bool Method2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "NS.MyCustomMarshaler", MarshalCookie="COOKIE4")]bool t); + [return: {|#4:MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "NS.MyCustomMarshaler", MarshalCookie="COOKIE3")|}] + public static partial bool {|#5:Method2|}([{|#6:MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "NS.MyCustomMarshaler", MarshalCookie="COOKIE4")|}]bool {|#7:t|}); } """; @@ -363,13 +363,13 @@ public ATTRIBUTELibraryImportAttribute(string a) { } partial class Test { [ATTRIBUTELibraryImportAttribute("DoesNotExist")] - public static partial void Method1(); + public static partial void {|CS8795:Method1|}(); [ATTRIBUTELibraryImport("DoesNotExist")] - public static partial void Method2(); + public static partial void {|CS8795:Method2|}(); [System.Runtime.InteropServices.ATTRIBUTELibraryImport("DoesNotExist")] - public static partial void Method3(); + public static partial void {|CS8795:Method3|}(); } """; @@ -385,12 +385,12 @@ public static string BasicParametersAndModifiersWithStringMarshalling(string typ {{preDeclaration}} partial class Test { - [LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.{{value}})] - public static partial {{typename}} Method( - {{typename}} p, - in {{typename}} pIn, - ref {{typename}} pRef, - out {{typename}} pOut); + [{|#0:LibraryImport("DoesNotExist", StringMarshalling = StringMarshalling.{{value}})|}] + public static partial {{typename}} {|#1:Method|}( + {{typename}} {|#2:p|}, + in {{typename}} {|#3:pIn|}, + ref {{typename}} {|#4:pRef|}, + out {{typename}} {|#5:pOut|}); } """; @@ -407,11 +407,11 @@ public static string BasicParametersAndModifiersWithStringMarshallingCustomType( partial class Test { [LibraryImport("DoesNotExist", StringMarshallingCustomType = typeof({{stringMarshallingCustomTypeName}}))] - public static partial {{typeName}} Method( - {{typeName}} p, - in {{typeName}} pIn, - ref {{typeName}} pRef, - out {{typeName}} pOut); + public static partial {{typeName}} {|#0:Method|}( + {{typeName}} {|#1:p|}, + in {{typeName}} {|#2:pIn|}, + ref {{typeName}} {|#3:pRef|}, + out {{typeName}} {|#4:pOut|}); } """; @@ -441,11 +441,11 @@ public static string BasicParametersAndModifiers(string typeName, string preDecl partial class Test { [LibraryImport("DoesNotExist")] - public static partial {{typeName}} Method( - {{typeName}} p, - in {{typeName}} pIn, - ref {{typeName}} pRef, - out {{typeName}} pOut); + public static partial {{typeName}} {|#0:Method|}( + {{typeName}} {|#1:p|}, + in {{typeName}} {|#2:pIn|}, + ref {{typeName}} {|#3:pRef|}, + out {{typeName}} {|#4:pOut|}); } """; @@ -459,10 +459,10 @@ public static string BasicParametersAndModifiersNoRef(string typeName, string pr partial class Test { [LibraryImport("DoesNotExist")] - public static partial {{typeName}} Method( - {{typeName}} p, - in {{typeName}} pIn, - out {{typeName}} pOut); + public static partial {{typeName}} {|#0:Method|}( + {{typeName}} {|#1:p|}, + in {{typeName}} {|#2:pIn|}, + out {{typeName}} {|#4:pOut|}); } """; @@ -475,11 +475,11 @@ public static string BasicParametersAndModifiersUnsafe(string typeName, string p partial class Test { [LibraryImport("DoesNotExist")] - public static unsafe partial {{typeName}} Method( - {{typeName}} p, - in {{typeName}} pIn, - ref {{typeName}} pRef, - out {{typeName}} pOut); + public static unsafe partial {{typeName}} {|#0:Method|}( + {{typeName}} {|#1:p|}, + in {{typeName}} {|#2:pIn|}, + ref {{typeName}} {|#3:pRef|}, + out {{typeName}} {|#4:pOut|}); } """; @@ -496,7 +496,7 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - [{{attributeName}}] {{typeName}} p); + [{{attributeName}}] {{typeName}} {|#0:p|}); } """; @@ -523,12 +523,12 @@ public static string MarshalAsParametersAndModifiers(string typeName, UnmanagedT partial class Test { [LibraryImport("DoesNotExist")] - [return: MarshalAs(UnmanagedType.{{unmanagedType}})] - public static partial {{typeName}} Method( - [MarshalAs(UnmanagedType.{{unmanagedType}})] {{typeName}} p, - [MarshalAs(UnmanagedType.{{unmanagedType}})] in {{typeName}} pIn, - [MarshalAs(UnmanagedType.{{unmanagedType}})] ref {{typeName}} pRef, - [MarshalAs(UnmanagedType.{{unmanagedType}})] out {{typeName}} pOut); + [return: {|#10:MarshalAs(UnmanagedType.{{unmanagedType}})|}] + public static partial {{typeName}} {|#0:Method|}( + [{|#11:MarshalAs(UnmanagedType.{{unmanagedType}})|}] {{typeName}} {|#1:p|}, + [{|#12:MarshalAs(UnmanagedType.{{unmanagedType}})|}] in {{typeName}} {|#2:pIn|}, + [{|#13:MarshalAs(UnmanagedType.{{unmanagedType}})|}] ref {{typeName}} {|#3:pRef|}, + [{|#14:MarshalAs(UnmanagedType.{{unmanagedType}})|}] out {{typeName}} {|#4:pOut|}); } """; @@ -541,11 +541,11 @@ partial class Test { [LibraryImport("DoesNotExist")] [return: MarshalAs(UnmanagedType.{{unmanagedType}})] - public static unsafe partial {{typeName}} Method( - [MarshalAs(UnmanagedType.{{unmanagedType}})] {{typeName}} p, - [MarshalAs(UnmanagedType.{{unmanagedType}})] in {{typeName}} pIn, - [MarshalAs(UnmanagedType.{{unmanagedType}})] ref {{typeName}} pRef, - [MarshalAs(UnmanagedType.{{unmanagedType}})] out {{typeName}} pOut); + public static unsafe partial {{typeName}} {|#0:Method|}( + [MarshalAs(UnmanagedType.{{unmanagedType}})] {{typeName}} {|#1:p|}, + [MarshalAs(UnmanagedType.{{unmanagedType}})] in {{typeName}} {|#2:pIn|}, + [MarshalAs(UnmanagedType.{{unmanagedType}})] ref {{typeName}} {|#3:pRef|}, + [MarshalAs(UnmanagedType.{{unmanagedType}})] out {{typeName}} {|#4:pOut|}); } """; @@ -629,13 +629,13 @@ partial class Test { [LibraryImport("DoesNotExist")] [return:MarshalAs(UnmanagedType.LPArray, SizeConst=10)] - public static partial {{elementType}}[] Method( - {{elementType}}[] p, - in {{elementType}}[] pIn, - int pRefSize, - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] ref {{elementType}}[] pRef, - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=5, SizeConst=4)] out {{elementType}}[] pOut, - out int pOutSize + public static partial {{elementType}}[] {|#0:Method|}( + {{elementType}}[] {|#1:p|}, + in {{elementType}}[] {|#2:pIn|}, + int {|#3:pRefSize|}, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] ref {{elementType}}[] {|#4:pRef|}, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=5, SizeConst=4)] out {{elementType}}[] {|#5:pOut|}, + out int {|#6:pOutSize|} ); } """; @@ -649,8 +649,8 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - {{(isByRef ? "ref" : "")}} {{sizeParamType}} pRefSize, - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ref int[] pRef + {{(isByRef ? "ref" : "")}} {{sizeParamType}} {|#0:pRefSize|}, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ref int[] {|#1:pRef|} ); } """; @@ -713,7 +713,7 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - {{byRefKind}} {{typeName}} p); + {{byRefKind}} {{typeName}} {|#0:p|}); } """; @@ -725,7 +725,7 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - {{typeName}} p); + {{typeName}} {|#0:p|}); } """; @@ -736,7 +736,7 @@ public static string BasicReturnType(string typeName, string preDeclaration = "" partial class Test { [LibraryImport("DoesNotExist")] - public static partial {{typeName}} Method(); + public static partial {{typeName}} {|#0:Method|}(); } """; @@ -987,7 +987,7 @@ partial class Test [LibraryImport("DoesNotExist")] public static partial void Method( int pRefSize, - [MarshalUsing(ConstantElementCount = 10, CountElementName = "pRefSize")] ref int[] pRef + [{|#0:MarshalUsing(ConstantElementCount = 10, CountElementName = "pRefSize")|}] ref int[] {|#1:pRef|} ); } """; @@ -1001,7 +1001,7 @@ partial class Test [LibraryImport("DoesNotExist")] public static partial void Method( int pRefSize, - [MarshalUsing(CountElementName = null)] ref int[] pRef + [{|#0:MarshalUsing(CountElementName = null)|}] ref int[] {|#1:pRef|} ); } """; @@ -1014,7 +1014,7 @@ partial class Test { [LibraryImport("DoesNotExist")] [return:MarshalUsing(ConstantElementCount=10)] - [return:MarshalAs(UnmanagedType.LPArray, SizeConst=10)] + [return:{|#0:MarshalAs(UnmanagedType.LPArray, SizeConst=10)|}] public static partial int[] Method(); } """; @@ -1026,7 +1026,7 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - [MarshalUsing(typeof(CustomIntMarshaller), ElementIndirectionDepth = 1)] [MarshalUsing(typeof(CustomIntMarshaller), ElementIndirectionDepth = 1)] TestCollection p); + [MarshalUsing(typeof(CustomIntMarshaller), ElementIndirectionDepth = 1)] [{|#0:MarshalUsing(typeof(CustomIntMarshaller), ElementIndirectionDepth = 1)|}] TestCollection p); } """ + CustomCollectionMarshallingCodeSnippets.TestCollection() @@ -1041,7 +1041,7 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - [MarshalUsing(typeof(CustomIntMarshaller), ElementIndirectionDepth = 2)] TestCollection p); + [{|#0:MarshalUsing(typeof(CustomIntMarshaller), ElementIndirectionDepth = 2)|}] TestCollection p); } """ + CustomCollectionMarshallingCodeSnippets.TestCollection() @@ -1055,8 +1055,8 @@ public static partial void Method( partial class Test { [LibraryImport("DoesNotExist")] - [return:MarshalUsing(CountElementName=MarshalUsingAttribute.ReturnsCountValue)] - public static partial int[] Method(); + [return:{|#0:MarshalUsing(CountElementName=MarshalUsingAttribute.ReturnsCountValue)|}] + public static partial int[] {|#1:Method|}(); } """; @@ -1068,7 +1068,7 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - [MarshalUsing(CountElementName="arr")] ref int[] arr + [{|#0:MarshalUsing(CountElementName="arr")|}] ref int[] {|#1:arr|} ); } """; @@ -1080,8 +1080,8 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - [MarshalUsing(CountElementName="arr2")] ref int[] arr, - [MarshalUsing(CountElementName="arr")] ref int[] arr2 + [{|#0:MarshalUsing(CountElementName="arr2")|}] ref int[] {|#1:arr|}, + [{|#2:MarshalUsing(CountElementName="arr")|}] ref int[] {|#3:arr2|} ); } """; @@ -1092,8 +1092,8 @@ partial class Test { [LibraryImport("DoesNotExist")] public static partial void Method( - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ref int[] arr, - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ref int[] arr2 + [{|#0:MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)|}] ref int[] {|#1:arr|}, + [{|#2:MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)|}] ref int[] {|#3:arr2|} ); } """; @@ -1210,9 +1210,9 @@ public static string RefReturn(string typeName) => $$""" partial struct Basic { [LibraryImport("DoesNotExist")] - public static partial ref {{typeName}} RefReturn(); + public static partial ref {{typeName}} {|#0:RefReturn|}(); [LibraryImport("DoesNotExist")] - public static partial ref readonly {{typeName}} RefReadonlyReturn(); + public static partial ref readonly {{typeName}} {|#1:RefReadonlyReturn|}(); } """; 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 ba39727cbfa60..b32c7aed94421 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop; using Microsoft.Interop.UnitTests; -using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Xunit; using StringMarshalling = System.Runtime.InteropServices.StringMarshalling; @@ -33,137 +32,798 @@ private static string ID( public static IEnumerable CodeSnippetsToCompile() { // Not LibraryImportAttribute - yield return new object[] { ID(), CodeSnippets.UserDefinedPrefixedAttributes, 0, 3 }; + yield return new object[] { ID(), CodeSnippets.UserDefinedPrefixedAttributes, Array.Empty() }; // No explicit marshalling for char or string - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParametersAndModifiers(), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParametersAndModifiers(), 5, 0 }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(), new[] + { + 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.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParametersAndModifiers(), new[] + { + 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.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(5) + .WithArguments("Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type.", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParametersAndModifiers(), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(5) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pOut") + }}; + + // No explicit marshalling for bool + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pOut") + }}; + + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParametersAndModifiers(), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(5) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pOut") + }}; - // No explicit marshaling for bool - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParametersAndModifiers(), 5, 0 }; // Unsupported StringMarshalling configuration - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiersWithStringMarshalling(StringMarshalling.Utf8), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiersWithStringMarshalling(StringMarshalling.Custom), 6, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiersWithStringMarshalling(StringMarshalling.Custom), 6, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomStringMarshallingParametersAndModifiers(), 5, 0 }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiersWithStringMarshalling(StringMarshalling.Utf8), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling char with 'StringMarshalling.Utf8' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling char with 'StringMarshalling.Utf8' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling char with 'StringMarshalling.Utf8' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling char with 'StringMarshalling.Utf8' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(5) + .WithArguments("Marshalling char with 'StringMarshalling.Utf8' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke.", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiersWithStringMarshalling(StringMarshalling.Custom), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidStringMarshallingConfiguration) + .WithLocation(0) + .WithArguments("Method", "'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'."), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(5) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiersWithStringMarshalling(StringMarshalling.Custom), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.InvalidStringMarshallingConfiguration) + .WithLocation(0) + .WithArguments("Method", "'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'."), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupported) + .WithLocation(1) + .WithArguments("string", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported) + .WithLocation(2) + .WithArguments("string", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported) + .WithLocation(3) + .WithArguments("string", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported) + .WithLocation(4) + .WithArguments("string", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported) + .WithLocation(5) + .WithArguments("string", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.CustomStringMarshallingParametersAndModifiers(), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'.", "pOut") + }}; // Unsupported UnmanagedType - yield return new object[] { ID(), CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.I1), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.U1), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.SafeArray), 10, 0 }; + yield return new object[] { ID(), CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.I1), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(0) + .WithArguments("MarshalAsAttribute", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(1) + .WithArguments("MarshalAsAttribute", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(2) + .WithArguments("MarshalAsAttribute", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(3) + .WithArguments("MarshalAsAttribute", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(4) + .WithArguments("MarshalAsAttribute", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.U1), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(0) + .WithArguments("MarshalAsAttribute", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(1) + .WithArguments("MarshalAsAttribute", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(2) + .WithArguments("MarshalAsAttribute", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(3) + .WithArguments("MarshalAsAttribute", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(4) + .WithArguments("MarshalAsAttribute", "pOut") + }}; + yield return new object[] { ID(), CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.SafeArray), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(10) + .WithArguments("SafeArray", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(11) + .WithArguments("SafeArray", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(12) + .WithArguments("SafeArray", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(13) + .WithArguments("SafeArray", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(14) + .WithArguments("SafeArray", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(0) + .WithArguments("MarshalAsAttribute", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(1) + .WithArguments("MarshalAsAttribute", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(2) + .WithArguments("MarshalAsAttribute", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(3) + .WithArguments("MarshalAsAttribute", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(4) + .WithArguments("MarshalAsAttribute", "pOut") + }}; // Unsupported MarshalAsAttribute usage // * UnmanagedType.CustomMarshaler, MarshalTypeRef, MarshalType, MarshalCookie - yield return new object[] { ID(), CodeSnippets.MarshalAsCustomMarshalerOnTypes, 16, 0 }; + yield return new object[] { ID(), CodeSnippets.MarshalAsCustomMarshalerOnTypes, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(0) + .WithArguments("CustomMarshaler", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(0) + .WithArguments("MarshalAsAttribute.MarshalCookie"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(0) + .WithArguments("MarshalAsAttribute.MarshalTypeRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(2) + .WithArguments("CustomMarshaler", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(2) + .WithArguments("MarshalAsAttribute.MarshalCookie"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(2) + .WithArguments("MarshalAsAttribute.MarshalTypeRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(4) + .WithArguments("CustomMarshaler", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(4) + .WithArguments("MarshalAsAttribute.MarshalCookie"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(4) + .WithArguments("MarshalAsAttribute.MarshalType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(6) + .WithArguments("CustomMarshaler", "UnmanagedType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(6) + .WithArguments("MarshalAsAttribute.MarshalCookie"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(6) + .WithArguments("MarshalAsAttribute.MarshalType"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(1) + .WithArguments("MarshalAsAttribute", "Method1"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(3) + .WithArguments("MarshalAsAttribute", "t"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(5) + .WithArguments("MarshalAsAttribute", "Method2"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterConfigurationNotSupported) + .WithLocation(7) + .WithArguments("MarshalAsAttribute", "t") + }}; // Unsupported [In, Out] attributes usage // Blittable array - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("Out"), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In, Out"), 1, 0 }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("Out"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter.", "p") + } }; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In, Out"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter.", "p") + } }; // By ref with [In, Out] attributes - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int", "In"), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In"), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In, Out"), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int", "Out"), 1, 0 }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int", "In"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") + } }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") + } }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In, Out"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") + } }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int", "Out"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") + } }; // By value non-array with [In, Out] attributes - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In"), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("Out"), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In, Out"), 1, 0 }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' attribute is not supported unless the '[Out]' attribute is also used. The behavior of the '[In]' attribute without the '[Out]' attribute is the same as the default behavior.", "p") + } }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("Out"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter.", "p") + } }; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In, Out"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter.", "p") + } }; // LCIDConversion - yield return new object[] { ID(), CodeSnippets.LCIDConversionAttribute, 1, 0 }; + yield return new object[] { ID(), CodeSnippets.LCIDConversionAttribute, new[] { + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) + .WithLocation(0) + .WithArguments("LCIDConversionAttribute") + } }; // No size information for array marshalling from unmanaged to managed // * return, out, ref - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 5, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; - yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), 3, 0 }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling string or char without explicit marshalling information is not supported. Specify 'LibraryImportAttribute.StringMarshalling', 'LibraryImportAttribute.StringMarshallingCustomType', 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(2) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pIn"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; + yield return new object[] { ID(), CodeSnippets.BasicParametersAndModifiers(CodeSnippets.DisableRuntimeMarshalling), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "Method"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(4) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pOut"), + } }; // Collection with non-integer size param - yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: false), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: false), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: false), 2, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalUsingArrayParameterWithSizeParam(isByRef: false), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalUsingArrayParameterWithSizeParam(isByRef: false), 1, 0 }; - yield return new object[] { ID(), CodeSnippets.MarshalUsingArrayParameterWithSizeParam(isByRef: false), 2, 0 }; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: false), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "pRef") + } }; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: false), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "pRef") + } }; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: false), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRefSize"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "pRef") + } }; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: true), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "pRef") + } }; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: true), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "pRef") + } }; + yield return new object[] { ID(), CodeSnippets.MarshalAsArrayParameterWithSizeParam(isByRef: true), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'.", "pRefSize"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "pRef") + } }; // Custom type marshalling with invalid members CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets()); - yield return new object[] { ID(), customStructMarshallingCodeSnippets.NonStaticMarshallerEntryPoint, 2, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.ManagedToNativeOnlyOutParameter, 1, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.ManagedToNativeOnlyReturnValue, 1, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyInParameter, 1, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.StackallocOnlyRefParameter, 1, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateful.ManagedToNativeOnlyOutParameter, 1, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateful.ManagedToNativeOnlyReturnValue, 1, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateful.NativeToManagedOnlyInParameter, 1, 0 }; - yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateful.StackallocOnlyRefParameter, 1, 0 }; - - // Abstract SafeHandle type by reference - yield return new object[] { ID(), CodeSnippets.BasicParameterWithByRefModifier("ref", "System.Runtime.InteropServices.SafeHandle"), 1, 0 }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.NonStaticMarshallerEntryPoint, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(0).WithArguments("S", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported).WithLocation(10).WithArguments(""), + } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.ManagedToNativeOnlyOutParameter, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type 'global::Marshaller' does not support it.", "p"), + } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.ManagedToNativeOnlyReturnValue, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type 'global::Marshaller' does not support it.", "Method"), + } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyInParameter, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type 'global::Marshaller' does not support it.", "p"), + } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.StackallocOnlyRefParameter, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type 'global::Marshaller' does not support it.", "p"), + } }; - // Collection with constant and element size parameter - yield return new object[] { ID(), CodeSnippets.MarshalUsingCollectionWithConstantAndElementCount, 2, 0 }; + // Abstract SafeHandle by reference + yield return new object[] { ID(), CodeSnippets.BasicParameterWithByRefModifier("ref", "System.Runtime.InteropServices.SafeHandle"), new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("An abstract type derived from 'SafeHandle' cannot be marshalled by reference. The provided type must be concrete.", "p"), + } }; + // Collection with constant and element size parameter + yield return new object[] { ID(), CodeSnippets.MarshalUsingCollectionWithConstantAndElementCount, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + } }; // Collection with null element size parameter name - yield return new object[] { ID(), CodeSnippets.MarshalUsingCollectionWithNullElementName, 2, 0 }; + yield return new object[] { ID(), CodeSnippets.MarshalUsingCollectionWithNullElementName, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationValueNotSupported) + .WithLocation(0) + .WithArguments("null", "CountElementName"), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.", "pRef"), + } }; // Generic collection marshaller has different arity than collection. CustomCollectionMarshallingCodeSnippets customCollectionMarshallingCodeSnippets = new(new CodeSnippets()); - yield return new object[] { ID(), customCollectionMarshallingCodeSnippets.Stateless.GenericCollectionMarshallingArityMismatch, 2, 0 }; - - yield return new object[] { ID(), CodeSnippets.MarshalAsAndMarshalUsingOnReturnValue, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomElementMarshallingDuplicateElementIndirectionDepth, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.CustomElementMarshallingUnusedElementIndirectionDepth, 1, 0 }; - yield return new object[] { ID(), CodeSnippets.RecursiveCountElementNameOnReturnValue, 2, 0 }; - yield return new object[] { ID(), CodeSnippets.RecursiveCountElementNameOnParameter, 2, 0 }; - yield return new object[] { ID(), CodeSnippets.MutuallyRecursiveCountElementNameOnParameter, 4, 0 }; - yield return new object[] { ID(), CodeSnippets.MutuallyRecursiveSizeParamIndexOnParameter, 4, 0 }; - - // Ref returns - yield return new object[] { ID(), CodeSnippets.RefReturn("int"), 2, 2 }; + yield return new object[] { ID(), customCollectionMarshallingCodeSnippets.Stateless.GenericCollectionMarshallingArityMismatch, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported) + .WithLocation(0) + .WithArguments("TestCollection", "p"), + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(10) + .WithArguments(""), + } }; + + yield return new object[] { ID(), CodeSnippets.MarshalAsAndMarshalUsingOnReturnValue, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + } }; + yield return new object[] { ID(), CodeSnippets.CustomElementMarshallingDuplicateElementIndirectionDepth, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + } }; + yield return new object[] { ID(), CodeSnippets.CustomElementMarshallingUnusedElementIndirectionDepth, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + } }; + yield return new object[] { ID(), CodeSnippets.RecursiveCountElementNameOnReturnValue, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "Method"), + } }; + yield return new object[] { ID(), CodeSnippets.RecursiveCountElementNameOnParameter, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "arr"), + } }; + yield return new object[] { ID(), CodeSnippets.MutuallyRecursiveCountElementNameOnParameter, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "arr"), + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(2) + .WithArguments(""), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "arr2"), + } }; + yield return new object[] { ID(), CodeSnippets.MutuallyRecursiveSizeParamIndexOnParameter, new[] + { + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(0) + .WithArguments(""), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(1) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "arr"), + VerifyCS.Diagnostic(GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported) + .WithLocation(2) + .WithArguments(""), + VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(3) + .WithArguments("The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.", "arr2"), + } }; + yield return new object[] { ID(), CodeSnippets.RefReturn("int"), new[] + { + DiagnosticResult.CompilerError("CS8795") + .WithLocation(0), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(0) + .WithArguments("ref return", "Basic.RefReturn()"), + DiagnosticResult.CompilerError("CS8795") + .WithLocation(1), + VerifyCS.Diagnostic(GeneratorDiagnostics.ReturnConfigurationNotSupported) + .WithLocation(1) + .WithArguments("ref return", "Basic.RefReadonlyReturn()"), + } }; } [Theory] [MemberData(nameof(CodeSnippetsToCompile))] - public async Task ValidateSnippets(string id, string source, int expectedGeneratorErrors, int expectedCompilerErrors) + public async Task ValidateSnippets(string id, string source, DiagnosticResult[] diagnostics) { TestUtils.Use(id); - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator()); - - // Verify the compilation failed with errors. - IEnumerable generatorErrors = generatorDiags.Where(d => d.Severity == DiagnosticSeverity.Error); - int generatorErrorCount = generatorErrors.Count(); - Assert.True( - expectedGeneratorErrors == generatorErrorCount, - $"Expected {expectedGeneratorErrors} errors, but encountered {generatorErrorCount}. Errors: {string.Join(Environment.NewLine, generatorErrors.Select(d => d.ToString()))}"); - - IEnumerable compilerErrors = newComp.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error); - int compilerErrorCount = compilerErrors.Count(); - Assert.True( - expectedCompilerErrors == compilerErrorCount, - $"Expected {expectedCompilerErrors} errors, but encountered {compilerErrorCount}. Errors: {string.Join(Environment.NewLine, compilerErrors.Select(d => d.ToString()))}"); + // Each snippet will contain the expected diagnostic codes in their expected locations for the compile errors. + // The test case will pass in the expected generator diagnostics. + await VerifyCS.VerifySourceGeneratorAsync(source, diagnostics); } public static IEnumerable CodeSnippetsToCompile_InvalidCode() From 216de88f99655704911882f4d877677499e14f09 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 17 Apr 2023 16:24:40 -0700 Subject: [PATCH 10/17] Convert over all no-diagnostic tests in the ComInterfaceGenerator test assembly. --- .../CallingConventionForwarding.cs | 161 ++++++----- .../ComClassGeneratorOutputShape.cs | 77 +++-- .../ComInterfaceGeneratorOutputShape.cs | 115 ++++---- .../CompileFails.cs | 240 ++++++++++++++++ .../Compiles.cs | 269 ++++++++---------- .../GeneratedComInterfaceAnalyzerTests.cs | 2 +- .../CSharpSourceGeneratorVerifier.cs | 2 +- 7 files changed, 555 insertions(+), 311 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs index a5e44816cb562..627d5f860eaf5 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs @@ -2,16 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Linq; using System.Reflection.Metadata; -using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; -using Microsoft.Interop.UnitTests; +using Microsoft.CodeAnalysis.Testing; using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + namespace ComInterfaceGenerator.Unit.Tests { public class CallingConventionForwarding @@ -31,16 +31,12 @@ partial interface INativeAPI : IUnmanagedInterfaceType void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); - var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); - - Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); - Assert.Empty(signature.UnmanagedCallingConventionTypes); + await VerifySourceGeneratorAsync(source, "INativeAPI", "Method", (compilation, signature) => + { + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Empty(signature.UnmanagedCallingConventionTypes); + }); } [Fact] @@ -59,16 +55,12 @@ partial interface INativeAPI : IUnmanagedInterfaceType void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); - - var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); - - Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); - Assert.Equal(newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition"), Assert.Single(signature.UnmanagedCallingConventionTypes), SymbolEqualityComparer.Default); + await VerifySourceGeneratorAsync(source, "INativeAPI", "Method", (newComp, signature) => + { + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Equal(newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition"), Assert.Single(signature.UnmanagedCallingConventionTypes), SymbolEqualityComparer.Default); + }); } [Fact] @@ -87,22 +79,19 @@ partial interface INativeAPI : IUnmanagedInterfaceType void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); - - var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); - - Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); - Assert.Empty(signature.UnmanagedCallingConventionTypes); + await VerifySourceGeneratorAsync(source, "INativeAPI", "Method", (_, signature) => + { + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Empty(signature.UnmanagedCallingConventionTypes); + }); } [Fact] public async Task SimpleUnmanagedCallConvAttributeForwarded() { string source = $$""" + using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; @@ -115,22 +104,19 @@ partial interface INativeAPI : IUnmanagedInterfaceType void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); - var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); - - Assert.Equal(SignatureCallingConvention.CDecl, signature.CallingConvention); - Assert.Empty(signature.UnmanagedCallingConventionTypes); + await VerifySourceGeneratorAsync(source, "INativeAPI", "Method", (_, signature) => + { + Assert.Equal(SignatureCallingConvention.CDecl, signature.CallingConvention); + Assert.Empty(signature.UnmanagedCallingConventionTypes); + }); } [Fact] public async Task ComplexUnmanagedCallConvAttributeForwarded() { string source = $$""" + using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; @@ -143,28 +129,25 @@ partial interface INativeAPI : IUnmanagedInterfaceType void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); - var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); - - Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); - Assert.Equal(new[] + await VerifySourceGeneratorAsync(source, "INativeAPI", "Method", (newComp, signature) => { - newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvCdecl"), - newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvMemberFunction"), - }, - signature.UnmanagedCallingConventionTypes, - SymbolEqualityComparer.Default); + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Equal(new[] + { + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvCdecl"), + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvMemberFunction"), + }, + signature.UnmanagedCallingConventionTypes, + SymbolEqualityComparer.Default); + }); } [Fact] public async Task ComplexUnmanagedCallConvAttributeWithSuppressGCTransitionForwarded() { string source = $$""" + using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; @@ -178,41 +161,67 @@ partial interface INativeAPI : IUnmanagedInterfaceType void Method(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); - - var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); + await VerifySourceGeneratorAsync(source, "INativeAPI", "Method", (newComp, signature) => + { + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Equal(new[] + { + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition"), + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvCdecl"), + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvMemberFunction"), + }, + signature.UnmanagedCallingConventionTypes, + SymbolEqualityComparer.Default); + }); + } - Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); - Assert.Equal(new[] + private static async Task VerifySourceGeneratorAsync(string source, string interfaceName, string methodName, Action signatureValidator) + { + CallingConventionForwardingTest test = new(interfaceName, methodName, signatureValidator) { - newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition"), - newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvCdecl"), - newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvMemberFunction"), - }, - signature.UnmanagedCallingConventionTypes, - SymbolEqualityComparer.Default); + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; + + await test.RunAsync(); } - private static async Task FindFunctionPointerInvocationSignature(Compilation compilation, string userDefinedInterfaceName, string methodName) + class CallingConventionForwardingTest : VerifyCS.Test { - INamedTypeSymbol? userDefinedInterface = compilation.Assembly.GetTypeByMetadataName(userDefinedInterfaceName); - Assert.NotNull(userDefinedInterface); + private readonly Action _signatureValidator; + private readonly string _interfaceName; + private readonly string _methodName; + + public CallingConventionForwardingTest(string interfaceName, string methodName, Action signatureValidator) + : base(referenceAncillaryInterop: true) + { + _signatureValidator = signatureValidator; + _interfaceName = interfaceName; + _methodName = methodName; + } + + protected override void VerifyFinalCompilation(Compilation compilation) + { + _signatureValidator(compilation, FindFunctionPointerInvocationSignature(compilation)); + } + private IMethodSymbol FindFunctionPointerInvocationSignature(Compilation compilation) + { + INamedTypeSymbol? userDefinedInterface = compilation.Assembly.GetTypeByMetadataName(_interfaceName); + Assert.NotNull(userDefinedInterface); - INamedTypeSymbol generatedInterfaceImplementation = Assert.Single(userDefinedInterface.GetTypeMembers("Native")); + INamedTypeSymbol generatedInterfaceImplementation = Assert.Single(userDefinedInterface.GetTypeMembers("Native")); - IMethodSymbol methodImplementation = Assert.Single(generatedInterfaceImplementation.GetMembers($"global::{userDefinedInterfaceName}.{methodName}").OfType()); + IMethodSymbol methodImplementation = Assert.Single(generatedInterfaceImplementation.GetMembers($"global::{_interfaceName}.{_methodName}").OfType()); - SyntaxNode emittedImplementationSyntax = await methodImplementation.DeclaringSyntaxReferences[0].GetSyntaxAsync(); + SyntaxNode emittedImplementationSyntax = methodImplementation.DeclaringSyntaxReferences[0].GetSyntax(); - SemanticModel model = compilation.GetSemanticModel(emittedImplementationSyntax.SyntaxTree); + SemanticModel model = compilation.GetSemanticModel(emittedImplementationSyntax.SyntaxTree); - IOperation body = model.GetOperation(emittedImplementationSyntax)!; + IOperation body = model.GetOperation(emittedImplementationSyntax)!; - return Assert.Single(body.Descendants().OfType()).GetFunctionPointerSignature(); + return Assert.Single(body.Descendants().OfType()).GetFunctionPointerSignature(); + } } } } 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 2bb8d5e187ea3..ce6da75ec5e72 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 @@ -5,9 +5,11 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.Interop.UnitTests; +using Microsoft.CodeAnalysis.Testing; using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + namespace ComInterfaceGenerator.Unit.Tests { public class ComClassGeneratorOutputShape @@ -27,15 +29,8 @@ partial interface INativeAPI [GeneratedComClass] partial class C : INativeAPI {} """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComClassGenerator()); - TestUtils.AssertPostSourceGeneratorCompilation(newComp); - // We'll create one syntax tree for the new interface. - Assert.Equal(comp.SyntaxTrees.Count() + 1, newComp.SyntaxTrees.Count()); - VerifyShape(newComp, "C"); + await VerifySourceGeneratorAsync(source, "C"); } [Fact] @@ -69,36 +64,56 @@ partial class E : C { } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComClassGenerator()); - TestUtils.AssertPostSourceGeneratorCompilation(newComp); - // We'll create one syntax tree per user-defined interface. - Assert.Equal(comp.SyntaxTrees.Count() + 3, newComp.SyntaxTrees.Count()); + await VerifySourceGeneratorAsync(source, "C", "D", "E"); + } + + private static async Task VerifySourceGeneratorAsync(string source, params string[] typeNames) + { + GeneratedShapeTest test = new(typeNames) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; - VerifyShape(newComp, "C"); - VerifyShape(newComp, "D"); - VerifyShape(newComp, "E"); + await test.RunAsync(); } - private static void VerifyShape(Compilation comp, string userDefinedClassMetadataName) + class GeneratedShapeTest : VerifyCS.Test { - INamedTypeSymbol? userDefinedClass = comp.Assembly.GetTypeByMetadataName(userDefinedClassMetadataName); - Assert.NotNull(userDefinedClass); + private readonly string[] _typeNames; - INamedTypeSymbol? comExposedClassAttribute = comp.GetTypeByMetadataName("System.Runtime.InteropServices.Marshalling.ComExposedClassAttribute`1"); + public GeneratedShapeTest(params string[] typeNames) + :base(referenceAncillaryInterop: true) + { + _typeNames = typeNames; + } - Assert.NotNull(comExposedClassAttribute); + protected override void VerifyFinalCompilation(Compilation compilation) + { + // Generate one source file per attributed interface. + Assert.Equal(TestState.Sources.Count + _typeNames.Length, compilation.SyntaxTrees.Count()); + Assert.All(_typeNames, name => VerifyShape(compilation, name)); + } - AttributeData iUnknownDerivedAttribute = Assert.Single( - userDefinedClass.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass?.OriginalDefinition, comExposedClassAttribute)); + private static void VerifyShape(Compilation comp, string userDefinedClassMetadataName) + { + INamedTypeSymbol? userDefinedClass = comp.Assembly.GetTypeByMetadataName(userDefinedClassMetadataName); + Assert.NotNull(userDefinedClass); - Assert.Collection(Assert.IsAssignableFrom(iUnknownDerivedAttribute.AttributeClass).TypeArguments, - infoType => - { - Assert.True(Assert.IsAssignableFrom(infoType).IsFileLocal); - }); + INamedTypeSymbol? comExposedClassAttribute = comp.GetTypeByMetadataName("System.Runtime.InteropServices.Marshalling.ComExposedClassAttribute`1"); + + Assert.NotNull(comExposedClassAttribute); + + AttributeData iUnknownDerivedAttribute = Assert.Single( + userDefinedClass.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass?.OriginalDefinition, comExposedClassAttribute)); + + Assert.Collection(Assert.IsAssignableFrom(iUnknownDerivedAttribute.AttributeClass).TypeArguments, + infoType => + { + Assert.True(Assert.IsAssignableFrom(infoType).IsFileLocal); + }); + } } } } 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 c2ea6ee6e063d..32728dace8742 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 @@ -8,12 +8,16 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using Microsoft; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Testing; using Microsoft.Interop.UnitTests; using Xunit; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + namespace ComInterfaceGenerator.Unit.Tests { public class ComInterfaceGeneratorOutputShape @@ -32,15 +36,8 @@ partial interface INativeAPI void Method2(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComInterfaceGenerator()); - TestUtils.AssertPostSourceGeneratorCompilation(newComp); - // We'll create one syntax tree for the new interface. - Assert.Equal(comp.SyntaxTrees.Count() + 1, newComp.SyntaxTrees.Count()); - VerifyShape(newComp, "INativeAPI"); + await VerifySourceGeneratorAsync(source, "INativeAPI"); } [Fact] @@ -63,16 +60,8 @@ partial interface J void Method2(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComInterfaceGenerator()); - TestUtils.AssertPostSourceGeneratorCompilation(newComp); - // We'll create one syntax tree per user-defined interface. - Assert.Equal(comp.SyntaxTrees.Count() + 2, newComp.SyntaxTrees.Count()); - VerifyShape(newComp, "I"); - VerifyShape(newComp, "J"); + await VerifySourceGeneratorAsync(source, "I", "J"); } [Fact] @@ -99,47 +88,67 @@ partial interface J void Method2(); } """; - Compilation comp = await TestUtils.CreateCompilation(source); - TestUtils.AssertPreSourceGeneratorCompilation(comp); - var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComInterfaceGenerator()); - TestUtils.AssertPostSourceGeneratorCompilation(newComp); - // We'll create one syntax tree per user-defined interface. - Assert.Equal(comp.SyntaxTrees.Count() + 3, newComp.SyntaxTrees.Count()); - - VerifyShape(newComp, "I"); - VerifyShape(newComp, "J"); + await VerifySourceGeneratorAsync(source, "I", "Empty", "J"); } - private static void VerifyShape(Compilation comp, string userDefinedInterfaceMetadataName) + private static async Task VerifySourceGeneratorAsync(string source, params string[] typeNames) { - INamedTypeSymbol? userDefinedInterface = comp.Assembly.GetTypeByMetadataName(userDefinedInterfaceMetadataName); - Assert.NotNull(userDefinedInterface); - - INamedTypeSymbol? iUnknownDerivedAttributeType = comp.GetTypeByMetadataName("System.Runtime.InteropServices.Marshalling.IUnknownDerivedAttribute`2"); - - Assert.NotNull(iUnknownDerivedAttributeType); + GeneratedShapeTest test = new(typeNames) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck + }; - AttributeData iUnknownDerivedAttribute = Assert.Single( - userDefinedInterface.GetAttributes(), - attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass?.OriginalDefinition, iUnknownDerivedAttributeType)); - - Assert.Collection(Assert.IsAssignableFrom(iUnknownDerivedAttribute.AttributeClass).TypeArguments, - infoType => - { - Assert.True(Assert.IsAssignableFrom(infoType).IsFileLocal); - }, - implementationType => - { - Assert.True(Assert.IsAssignableFrom(implementationType).IsFileLocal); - Assert.Contains(userDefinedInterface, implementationType.Interfaces, SymbolEqualityComparer.Default); - Assert.Contains(implementationType.GetAttributes(), attr => attr.AttributeClass?.ToDisplayString() == typeof(DynamicInterfaceCastableImplementationAttribute).FullName); - Assert.All(userDefinedInterface.GetMembers().OfType().Where(method => method.IsAbstract && !method.IsStatic), - method => - { - Assert.NotNull(implementationType.FindImplementationForInterfaceMember(method)); - }); - }); + await test.RunAsync(); + } + class GeneratedShapeTest : VerifyCS.Test + { + private readonly string[] _typeNames; + + public GeneratedShapeTest(params string[] typeNames) + : base(referenceAncillaryInterop: true) + { + _typeNames = typeNames; + } + + protected override void VerifyFinalCompilation(Compilation compilation) + { + // Generate one source file per attributed interface. + Assert.Equal(TestState.Sources.Count + _typeNames.Length, compilation.SyntaxTrees.Count()); + Assert.All(_typeNames, name => VerifyShape(compilation, name)); + } + + private static void VerifyShape(Compilation comp, string userDefinedInterfaceMetadataName) + { + INamedTypeSymbol? userDefinedInterface = comp.Assembly.GetTypeByMetadataName(userDefinedInterfaceMetadataName); + Assert.NotNull(userDefinedInterface); + + INamedTypeSymbol? iUnknownDerivedAttributeType = comp.GetTypeByMetadataName("System.Runtime.InteropServices.Marshalling.IUnknownDerivedAttribute`2"); + + Assert.NotNull(iUnknownDerivedAttributeType); + + AttributeData iUnknownDerivedAttribute = Assert.Single( + userDefinedInterface.GetAttributes(), + attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass?.OriginalDefinition, iUnknownDerivedAttributeType)); + + Assert.Collection(Assert.IsAssignableFrom(iUnknownDerivedAttribute.AttributeClass).TypeArguments, + infoType => + { + Assert.True(Assert.IsAssignableFrom(infoType).IsFileLocal); + }, + implementationType => + { + Assert.True(Assert.IsAssignableFrom(implementationType).IsFileLocal); + Assert.Contains(userDefinedInterface, implementationType.Interfaces, SymbolEqualityComparer.Default); + Assert.Contains(implementationType.GetAttributes(), attr => attr.AttributeClass?.ToDisplayString() == typeof(DynamicInterfaceCastableImplementationAttribute).FullName); + Assert.All(userDefinedInterface.GetMembers().OfType().Where(method => method.IsAbstract && !method.IsStatic), + method => + { + Assert.NotNull(implementationType.FindImplementationForInterfaceMember(method)); + }); + }); + } } } } 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 new file mode 100644 index 0000000000000..7c7bcb031ac77 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs @@ -0,0 +1,240 @@ +// 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.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.Interop.UnitTests; +using Xunit; + +using VerifyVTableGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; +using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; +using Microsoft.CodeAnalysis.Testing; + +namespace ComInterfaceGenerator.Unit.Tests +{ + public class CompileFails + { + private static string ID( + [CallerLineNumber] int lineNumber = 0, + [CallerFilePath] string? filePath = null) + => TestUtils.GetFileLineName(lineNumber, filePath); + + private static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind generator) + => generator switch + { + GeneratorKind.VTableIndexStubGenerator => new VirtualMethodIndexAttributeProvider(), + GeneratorKind.ComInterfaceGenerator => new GeneratedComInterfaceAttributeProvider(), + _ => throw new UnreachableException(), + }; + + public static IEnumerable ManagedToUnmanagedCodeSnippetsToCompile(GeneratorKind generator) + { + CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); + + // SafeHandles + yield return new[] { ID(), codeSnippets.BasicParametersAndModifiersManagedToUnmanaged("Microsoft.Win32.SafeHandles.SafeFileHandle") }; + + // Custom type marshalling managed-to-unmanaged + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsManagedToUnmanaged = new(new CodeSnippets.ManagedToUnmanaged(GetAttributeProvider(generator))); + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyOutParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedFinallyOnlyOutParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyReturnValue }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedFinallyOnlyReturnValue }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.PinByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.StackallocByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.RefParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.StackallocParametersAndModifiersNoRef }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.OptionalStackallocParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.DefaultModeByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.DefaultModeReturnValue }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ParametersAndModifiersWithFree }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ParametersAndModifiersWithOnInvoked }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyOutParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedFinallyOnlyOutParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyReturnValue }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedFinallyOnlyReturnValue }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.StackallocByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.PinByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.MarshallerPinByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.RefParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.StackallocParametersAndModifiersNoRef }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.OptionalStackallocParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.DefaultModeByValueInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.DefaultModeReturnValue }; + } + + public static IEnumerable UnmanagedToManagedCodeSnippetsToCompile(GeneratorKind generator) + { + // Custom type marshalling unmanaged-to-managed + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsUnmanagedToManaged = new(new CodeSnippets.UnmanagedToManaged(GetAttributeProvider(generator))); + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.ParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.NativeToManagedOnlyInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.NativeToManagedFinallyOnlyInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.ByValueOutParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.RefParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.OptionalStackallocParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ParametersAndModifiersWithFree }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ParametersAndModifiersWithOnInvoked }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.NativeToManagedOnlyInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.NativeToManagedFinallyOnlyInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ByValueOutParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.RefParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.OptionalStackallocParametersAndModifiers }; + } + + public static IEnumerable CustomCollectionsManagedToUnmanaged(GeneratorKind generator) + { + CustomCollectionMarshallingCodeSnippets customCollectionMarshallingCodeSnippetsManagedToUnmanaged = new(new CodeSnippets.ManagedToUnmanaged(GetAttributeProvider(generator))); + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyOutParameter() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyReturnValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NonBlittableElementByValue }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NonBlittableElementNativeToManagedOnlyOutParameter }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NonBlittableElementNativeToManagedOnlyReturnValue }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyOutParameter() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyReturnValue() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementByValue }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementNativeToManagedOnlyOutParameter }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementNativeToManagedOnlyReturnValue }; + } + + [Theory] + [MemberData(nameof(ManagedToUnmanagedCodeSnippetsToCompile), GeneratorKind.ComInterfaceGenerator)] + [MemberData(nameof(UnmanagedToManagedCodeSnippetsToCompile), GeneratorKind.ComInterfaceGenerator)] + [MemberData(nameof(CustomCollectionsManagedToUnmanaged), GeneratorKind.ComInterfaceGenerator)] + public async Task ValidateComInterfaceSnippets(string id, string source) + { + _ = id; + VerifyComInterfaceGenerator.Test test = new(referenceAncillaryInterop: true) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck, + // Our fallback mechanism for invalid code for unmanaged->managed stubs sometimes generates invalid code. + CompilerDiagnostics = CompilerDiagnostics.None, + }; + await test.RunAsync(); + //Compilation comp = await TestUtils.CreateCompilation(source); + //// Allow the Native nested type name to be missing in the pre-source-generator compilation + //// We allow duplicate usings here since some of the shared snippets add a using for System.Runtime.InteropServices.Marshalling when we already have one in our base snippets. + //TestUtils.AssertPreSourceGeneratorCompilation(comp, "CS0426", "CS0105"); + + //var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.ComInterfaceGenerator()); + //Assert.Empty(generatorDiags.Where(IsValidGeneratorDiagnostic)); + + //List allowedDiagnostics = new() + //{ + // // Duplicate 'using' + // "CS0105", + // // Variable assigned to but never read + // "CS0219" + //}; + //// There are valid warnings from the generator -- + //if (generatorDiags.Length != 0) + //{ + // List additionalDiags = new() { + // // No overload for 'ABI_Method' matches function pointer 'delegate* unmanaged<...>' + // "CS8757", + // // Cannot use 'parameterType' as a parameter type on a method attributed with 'UnmanagedCallersOnly'. + // "CS8894", + // // The out parameter 'paramName' must be assigned to before control leaves the current method + // "CS0177", + // // Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. + // "CS8977", + // // The type 'SafeFileHandle' must be a non-nullable value type, along with all fields at any level of nesting, + // // in order to use it as parameter 'T' in the generic type or method 'ExceptionAsDefaultMarshaller' + // "CS8377", + // // Argument N may not be passed with the 'in' keyword + // "CS1615" + // }; + // allowedDiagnostics.AddRange(additionalDiags); + //} + + //TestUtils.AssertPostSourceGeneratorCompilation(newComp, allowedDiagnostics.ToArray()); + } + } +} 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 e6448b6972859..eba026c92e440 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 @@ -11,6 +11,10 @@ using Microsoft.Interop.UnitTests; using Xunit; +using VerifyVTableGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; +using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; +using Microsoft.CodeAnalysis.Testing; + namespace ComInterfaceGenerator.Unit.Tests { public class Compiles @@ -61,6 +65,39 @@ public static IEnumerable CodeSnippetsToCompile(GeneratorKind generato yield return new[] { ID(), codeSnippets.BasicParametersAndModifiersNoImplicitThis() }; yield return new[] { ID(), codeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + // Custom type marshalling bidirectional + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsBidirectional = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.ParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.RefParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.OptionalStackallocParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.ParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.ParametersAndModifiersWithFree }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.ParametersAndModifiersWithOnInvoked }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.RefParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.OptionalStackallocParametersAndModifiers }; + + // Exception Handling + // HResult + yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("int") }; + yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("uint") }; + // NaN + yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("float") }; + yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("double") }; + // Default Value + yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("nint") }; + // Void + yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("void") }; + } + + public static IEnumerable ManagedToUnmanagedCodeSnippetsToCompile(GeneratorKind generator) + { + CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); + + // SafeHandles + yield return new[] { ID(), codeSnippets.BasicParametersAndModifiersManagedToUnmanaged("Microsoft.Win32.SafeHandles.SafeFileHandle") }; + // Custom type marshalling managed-to-unmanaged CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsManagedToUnmanaged = new(new CodeSnippets.ManagedToUnmanaged(GetAttributeProvider(generator))); yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ParametersAndModifiers }; @@ -94,7 +131,10 @@ public static IEnumerable CodeSnippetsToCompile(GeneratorKind generato yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.OptionalStackallocParametersAndModifiers }; yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.DefaultModeByValueInParameter }; yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.DefaultModeReturnValue }; + } + public static IEnumerable UnmanagedToManagedCodeSnippetsToCompile(GeneratorKind generator) + { // Custom type marshalling unmanaged-to-managed CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsUnmanagedToManaged = new(new CodeSnippets.UnmanagedToManaged(GetAttributeProvider(generator))); yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.ParametersAndModifiers }; @@ -113,39 +153,85 @@ public static IEnumerable CodeSnippetsToCompile(GeneratorKind generato yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ByValueOutParameter }; yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.RefParameter }; yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.OptionalStackallocParametersAndModifiers }; - - // Custom type marshalling bidirectional - CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsBidirectional = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.ParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.MarshalUsingParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.RefParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateless.OptionalStackallocParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.ParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.ParametersAndModifiersWithFree }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.ParametersAndModifiersWithOnInvoked }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.MarshalUsingParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.RefParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsBidirectional.Stateful.OptionalStackallocParametersAndModifiers }; - - // SafeHandles - yield return new[] { ID(), codeSnippets.BasicParametersAndModifiersManagedToUnmanaged("Microsoft.Win32.SafeHandles.SafeFileHandle") }; - - // Exception Handling - // HResult - yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("int") }; - yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("uint") }; - // NaN - yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("float") }; - yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("double") }; - // Default Value - yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("nint") }; - // Void - yield return new[] { ID(), codeSnippets.BasicReturnTypeComExceptionHandling("void") }; } public static IEnumerable CustomCollections(GeneratorKind generator) { // Custom collection marshalling + CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + + CustomCollectionMarshallingCodeSnippets customCollectionMarshallingCodeSnippetsBidirectional = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerReturnValueLength() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.NestedMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.NonBlittableElementParametersAndModifiers }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomElementMarshalling }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerReturnValueLength() }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.NonBlittableElementParametersAndModifiers }; + yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomElementMarshalling }; + } + + public static IEnumerable CustomCollectionsManagedToUnmanaged(GeneratorKind generator) + { CustomCollectionMarshallingCodeSnippets customCollectionMarshallingCodeSnippetsManagedToUnmanaged = new(new CodeSnippets.ManagedToUnmanaged(GetAttributeProvider(generator))); yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; @@ -229,94 +315,19 @@ public static IEnumerable CustomCollections(GeneratorKind generator) yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementByValue }; yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementNativeToManagedOnlyOutParameter }; yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementNativeToManagedOnlyReturnValue }; - - CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - yield return new[] { ID(), codeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; - - CustomCollectionMarshallingCodeSnippets customCollectionMarshallingCodeSnippetsBidirectional = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomMarshallerReturnValueLength() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.NestedMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.NonBlittableElementParametersAndModifiers }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateless.CustomElementMarshalling }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.DefaultMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerParametersAndModifiers() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomMarshallerReturnValueLength() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.NonBlittableElementParametersAndModifiers }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsBidirectional.Stateful.CustomElementMarshalling }; } [Theory] [MemberData(nameof(CodeSnippetsToCompile), GeneratorKind.VTableIndexStubGenerator)] + [MemberData(nameof(ManagedToUnmanagedCodeSnippetsToCompile), GeneratorKind.VTableIndexStubGenerator)] + [MemberData(nameof(UnmanagedToManagedCodeSnippetsToCompile), GeneratorKind.VTableIndexStubGenerator)] + [MemberData(nameof(CustomCollectionsManagedToUnmanaged), GeneratorKind.VTableIndexStubGenerator)] + [MemberData(nameof(CustomCollections), GeneratorKind.VTableIndexStubGenerator)] [MemberData(nameof(CustomCollections), GeneratorKind.VTableIndexStubGenerator)] public async Task ValidateVTableIndexSnippets(string id, string source) { _ = id; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - // We allow duplicate usings here since some of the shared snippets add a using for System.Runtime.InteropServices.Marshalling when we already have one in our base snippets. - TestUtils.AssertPreSourceGeneratorCompilation(comp, "CS0426", "CS0105"); - - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.VtableIndexStubGenerator()); - Assert.Empty(generatorDiags); - - TestUtils.AssertPostSourceGeneratorCompilation(newComp, "CS0105"); + await VerifyVTableGenerator.VerifySourceGeneratorWithAncillaryInteropAsync(source); } [Theory] @@ -325,48 +336,8 @@ public async Task ValidateVTableIndexSnippets(string id, string source) public async Task ValidateComInterfaceSnippets(string id, string source) { _ = id; - Compilation comp = await TestUtils.CreateCompilation(source); - // Allow the Native nested type name to be missing in the pre-source-generator compilation - // We allow duplicate usings here since some of the shared snippets add a using for System.Runtime.InteropServices.Marshalling when we already have one in our base snippets. - TestUtils.AssertPreSourceGeneratorCompilation(comp, "CS0426", "CS0105"); - var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.ComInterfaceGenerator()); - Assert.Empty(generatorDiags.Where(IsValidGeneratorDiagnostic)); - - List allowedDiagnostics = new() - { - // Duplicate 'using' - "CS0105", - // Variable assigned to but never read - "CS0219" - }; - // There are valid warnings from the generator -- - if (generatorDiags.Length != 0) - { - List additionalDiags = new() { - // No overload for 'ABI_Method' matches function pointer 'delegate* unmanaged<...>' - "CS8757", - // Cannot use 'parameterType' as a parameter type on a method attributed with 'UnmanagedCallersOnly'. - "CS8894", - // The out parameter 'paramName' must be assigned to before control leaves the current method - "CS0177", - // Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - "CS8977", - // The type 'SafeFileHandle' must be a non-nullable value type, along with all fields at any level of nesting, - // in order to use it as parameter 'T' in the generic type or method 'ExceptionAsDefaultMarshaller' - "CS8377", - // Argument N may not be passed with the 'in' keyword - "CS1615" - }; - allowedDiagnostics.AddRange(additionalDiags); - } - - TestUtils.AssertPostSourceGeneratorCompilation(newComp, allowedDiagnostics.ToArray()); + await VerifyComInterfaceGenerator.VerifySourceGeneratorWithAncillaryInteropAsync(source); } - - private bool IsValidGeneratorDiagnostic(Diagnostic diag) - => diag.Id != "SYSLIB1051" - && diag.GetMessage().Contains("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '") - && diag.GetMessage().Contains("' does not support it. The generated source will not handle marshalling of parameter"); } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs index a77166a211d7c..1258854a44c2c 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs @@ -7,7 +7,7 @@ using Microsoft.Interop.Analyzers; using Xunit; -using VerifyCS = LibraryImportGenerator.UnitTests.Verifiers.CSharpAnalyzerVerifier; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpAnalyzerVerifier; namespace ComInterfaceGenerator.Unit.Tests { 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 abf7d23322754..167f00029ed45 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/Verifiers/CSharpSourceGeneratorVerifier.cs @@ -67,7 +67,7 @@ public static async Task VerifySourceGeneratorWithAncillaryInteropAsync(string s public static async Task VerifySourceGeneratorAsync(string[] sources, params DiagnosticResult[] expected) { - var test = new Test(referenceAncillaryInterop: true) + var test = new Test(referenceAncillaryInterop: false) { TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck }; From 44ee8af4886e4657e4d10b40723646366dccb562 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 17 Apr 2023 16:49:23 -0700 Subject: [PATCH 11/17] Forward byref modifiers to the inner function pointer when using the forwarder fallback. This fixes the last compile error we have for invalid managed->unmanaged stubs. --- .../ManagedToNativeVTableMethodGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs index 482cc2bc5c9bd..cfccdd1c3aba4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs @@ -225,7 +225,7 @@ private ParenthesizedExpressionSyntax CreateFunctionPointerExpression( { List functionPointerParameters = new(); var (paramList, retType, _) = _marshallers.GenerateTargetMethodSignatureData(_context); - functionPointerParameters.AddRange(paramList.Parameters.Select(p => FunctionPointerParameter(p.Type))); + functionPointerParameters.AddRange(paramList.Parameters.Select(p => FunctionPointerParameter(attributeLists: default, p.Modifiers, p.Type))); functionPointerParameters.Add(FunctionPointerParameter(retType)); // ((delegate* unmanaged<...>)) From 374c917af38d8233bcd685959b13351b12260214 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 17 Apr 2023 17:06:07 -0700 Subject: [PATCH 12/17] Enable a set of directed tests for invalid marshal modes in the CompileFails test suite. --- .../CodeSnippets.cs | 2 +- .../CompileFails.cs | 238 +++++------------- .../IVirtualMethodIndexSignatureProvider.cs | 6 +- 3 files changed, 61 insertions(+), 185 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs index d4406ea4a51fe..edef4fff73aac 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs @@ -126,7 +126,7 @@ public string BasicParametersAndModifiers(string typeName, string preDeclaration partial interface INativeAPI { {{VirtualMethodIndex(0)}} - {{typeName}} Method({{typeName}} value, in {{typeName}} inValue, ref {{typeName}} refValue, out {{typeName}} outValue); + {{typeName}} {|#0:Method|}({{typeName}} {|#1:value|}, in {{typeName}} {|#2:inValue|}, ref {{typeName}} {|#3:refValue|}, out {{typeName}} {|#4:outValue|}); } {{_attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI")}} """; 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 7c7bcb031ac77..99c9d3737f73c 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 @@ -11,9 +11,9 @@ using Microsoft.Interop.UnitTests; using Xunit; -using VerifyVTableGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; using Microsoft.CodeAnalysis.Testing; +using Microsoft.Interop; namespace ComInterfaceGenerator.Unit.Tests { @@ -32,209 +32,85 @@ private static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind _ => throw new UnreachableException(), }; - public static IEnumerable ManagedToUnmanagedCodeSnippetsToCompile(GeneratorKind generator) + public static IEnumerable InvalidUnmanagedToManagedCodeSnippetsToCompile(GeneratorKind generator) { CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); // SafeHandles - yield return new[] { ID(), codeSnippets.BasicParametersAndModifiersManagedToUnmanaged("Microsoft.Win32.SafeHandles.SafeFileHandle") }; + yield return new object[] { ID(), codeSnippets.BasicParametersAndModifiers("Microsoft.Win32.SafeHandles.SafeFileHandle"), new[] + { + // /0/Test0.cs(13,48): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method 'Method'. + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupported).WithLocation(0).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "Method"), + // /0/Test0.cs(13,98): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'value'. + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(1).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "value"), + // /0/Test0.cs(13,151): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'inValue'. + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(2).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "inValue"), + // /0/Test0.cs(13,207): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'refValue'. + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(3).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "refValue"), + // /0/Test0.cs(13,264): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'outValue'. + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(4).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "outValue"), + } }; - // Custom type marshalling managed-to-unmanaged - CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsManagedToUnmanaged = new(new CodeSnippets.ManagedToUnmanaged(GetAttributeProvider(generator))); - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.MarshalUsingParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyOutParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedFinallyOnlyOutParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyReturnValue }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedFinallyOnlyReturnValue }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.PinByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.StackallocByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.RefParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.StackallocParametersAndModifiersNoRef }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.OptionalStackallocParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.DefaultModeByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateless.DefaultModeReturnValue }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ParametersAndModifiersWithFree }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ParametersAndModifiersWithOnInvoked }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.MarshalUsingParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyOutParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedFinallyOnlyOutParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyReturnValue }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedFinallyOnlyReturnValue }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.StackallocByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.PinByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.MarshallerPinByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.RefParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.StackallocParametersAndModifiersNoRef }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.OptionalStackallocParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.DefaultModeByValueInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsManagedToUnmanaged.Stateful.DefaultModeReturnValue }; - } - public static IEnumerable UnmanagedToManagedCodeSnippetsToCompile(GeneratorKind generator) - { - // Custom type marshalling unmanaged-to-managed - CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippetsUnmanagedToManaged = new(new CodeSnippets.UnmanagedToManaged(GetAttributeProvider(generator))); - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.ParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.MarshalUsingParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.NativeToManagedOnlyInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.NativeToManagedFinallyOnlyInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.ByValueOutParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.RefParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateless.OptionalStackallocParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ParametersAndModifiersWithFree }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ParametersAndModifiersWithOnInvoked }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.MarshalUsingParametersAndModifiers }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.NativeToManagedOnlyInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.NativeToManagedFinallyOnlyInParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.ByValueOutParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.RefParameter }; - yield return new[] { ID(), customStructMarshallingCodeSnippetsUnmanagedToManaged.Stateful.OptionalStackallocParametersAndModifiers }; + // Marshallers with only support for their expected places in the signatures in + // ManagedToUnmanaged marshal modes. + + DiagnosticResult invalidManagedToUnmanagedParameterDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type 'global::Marshaller' does not support it.", "value"); + DiagnosticResult invalidUnmanagedToManagedParameterDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type 'global::Marshaller' does not support it.", "value"); + DiagnosticResult invalidReturnTypeDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type 'global::Marshaller' does not support it.", "Method"); + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyOutParameter, new[] { invalidManagedToUnmanagedParameterDiagnostic } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyReturnValue, new[] { invalidReturnTypeDiagnostic } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.ByValueInParameter, new[] { invalidUnmanagedToManagedParameterDiagnostic } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateful.NativeToManagedOnlyOutParameter, new[] { invalidManagedToUnmanagedParameterDiagnostic } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateful.NativeToManagedOnlyReturnValue, new[] { invalidReturnTypeDiagnostic } }; + yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateful.ByValueInParameter, new[] { invalidUnmanagedToManagedParameterDiagnostic } }; } - public static IEnumerable CustomCollectionsManagedToUnmanaged(GeneratorKind generator) + public static IEnumerable InvalidManagedToUnmanagedCodeSnippetsToCompile(GeneratorKind generator) { - CustomCollectionMarshallingCodeSnippets customCollectionMarshallingCodeSnippetsManagedToUnmanaged = new(new CodeSnippets.ManagedToUnmanaged(GetAttributeProvider(generator))); - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueCallerAllocatedBuffer() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.ByValueWithStaticPinning() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyOutParameter() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NativeToManagedOnlyReturnValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NonBlittableElementByValue }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NonBlittableElementNativeToManagedOnlyOutParameter }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateless.NonBlittableElementNativeToManagedOnlyReturnValue }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyOutParameter() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NativeToManagedOnlyReturnValue() }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementByValue }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementNativeToManagedOnlyOutParameter }; - yield return new[] { ID(), customCollectionMarshallingCodeSnippetsManagedToUnmanaged.Stateful.NonBlittableElementNativeToManagedOnlyReturnValue }; + // Marshallers with only support for their expected places in the signatures in + // UnmanagedToManaged marshal modes. + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + + yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateless.ByValueOutParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateful.NativeToManagedOnlyInParameter }; + yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateful.ByValueOutParameter }; } [Theory] - [MemberData(nameof(ManagedToUnmanagedCodeSnippetsToCompile), GeneratorKind.ComInterfaceGenerator)] - [MemberData(nameof(UnmanagedToManagedCodeSnippetsToCompile), GeneratorKind.ComInterfaceGenerator)] - [MemberData(nameof(CustomCollectionsManagedToUnmanaged), GeneratorKind.ComInterfaceGenerator)] - public async Task ValidateComInterfaceSnippets(string id, string source) + [MemberData(nameof(InvalidUnmanagedToManagedCodeSnippetsToCompile), GeneratorKind.ComInterfaceGenerator)] + public async Task ValidateInvalidUnmanagedToManagedCodeSnippets(string id, string source, DiagnosticResult[] expectedDiagnostics) { _ = id; VerifyComInterfaceGenerator.Test test = new(referenceAncillaryInterop: true) { TestCode = source, - TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, // Our fallback mechanism for invalid code for unmanaged->managed stubs sometimes generates invalid code. CompilerDiagnostics = CompilerDiagnostics.None, }; + test.ExpectedDiagnostics.AddRange(expectedDiagnostics); await test.RunAsync(); - //Compilation comp = await TestUtils.CreateCompilation(source); - //// Allow the Native nested type name to be missing in the pre-source-generator compilation - //// We allow duplicate usings here since some of the shared snippets add a using for System.Runtime.InteropServices.Marshalling when we already have one in our base snippets. - //TestUtils.AssertPreSourceGeneratorCompilation(comp, "CS0426", "CS0105"); - - //var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.ComInterfaceGenerator()); - //Assert.Empty(generatorDiags.Where(IsValidGeneratorDiagnostic)); + } - //List allowedDiagnostics = new() - //{ - // // Duplicate 'using' - // "CS0105", - // // Variable assigned to but never read - // "CS0219" - //}; - //// There are valid warnings from the generator -- - //if (generatorDiags.Length != 0) - //{ - // List additionalDiags = new() { - // // No overload for 'ABI_Method' matches function pointer 'delegate* unmanaged<...>' - // "CS8757", - // // Cannot use 'parameterType' as a parameter type on a method attributed with 'UnmanagedCallersOnly'. - // "CS8894", - // // The out parameter 'paramName' must be assigned to before control leaves the current method - // "CS0177", - // // Cannot use 'ref', 'in', or 'out' in the signature of a method attributed with 'UnmanagedCallersOnly'. - // "CS8977", - // // The type 'SafeFileHandle' must be a non-nullable value type, along with all fields at any level of nesting, - // // in order to use it as parameter 'T' in the generic type or method 'ExceptionAsDefaultMarshaller' - // "CS8377", - // // Argument N may not be passed with the 'in' keyword - // "CS1615" - // }; - // allowedDiagnostics.AddRange(additionalDiags); - //} + [Theory] + [MemberData(nameof(InvalidManagedToUnmanagedCodeSnippetsToCompile), GeneratorKind.ComInterfaceGenerator)] + public async Task ValidateInvalidManagedToUnmanagedCodeSnippets(string id, string source) + { + _ = id; - //TestUtils.AssertPostSourceGeneratorCompilation(newComp, allowedDiagnostics.ToArray()); + DiagnosticResult expectedDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type 'global::Marshaller' does not support it.", "value"); + await VerifyComInterfaceGenerator.VerifySourceGeneratorWithAncillaryInteropAsync(source, expectedDiagnostic); } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/IVirtualMethodIndexSignatureProvider.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/IVirtualMethodIndexSignatureProvider.cs index 5d4587a04d19b..04746077763d2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/IVirtualMethodIndexSignatureProvider.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/IVirtualMethodIndexSignatureProvider.cs @@ -67,7 +67,7 @@ string ICustomMarshallingSignatureTestProvider.BasicParameterByValue(string type partial interface INativeAPI { {{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}} - void Method({{typeName}} value); + void Method({{typeName}} {|#0:value|}); } {{AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI")}} """; @@ -85,7 +85,7 @@ string ICustomMarshallingSignatureTestProvider.BasicParameterWithByRefModifier(s partial interface INativeAPI { {{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}} - void Method({{modifier}} {{typeName}} value); + void Method({{modifier}} {{typeName}} {|#0:value|}); } {{AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI")}} """; @@ -100,7 +100,7 @@ string ICustomMarshallingSignatureTestProvider.BasicReturnType(string typeName, partial interface INativeAPI { {{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}} - {{typeName}} Method(); + {{typeName}} {|#0:Method|}(); } {{AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI")}} """; From 625c6ac3fd0e586231b8457590a3a258645994d4 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 18 Apr 2023 11:18:14 -0700 Subject: [PATCH 13/17] Remove test markup from tests that don't use the unit testing apis --- .../IncrementalGenerationTests.cs | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) 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 27df3c92b16ca..78ed48e8c0e44 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs @@ -3,12 +3,15 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Microsoft.Interop.UnitTests; using Xunit; using static Microsoft.Interop.LibraryImportGenerator; @@ -19,13 +22,10 @@ public class IncrementalGenerationTests { private static readonly GeneratorDriverOptions EnableIncrementalTrackingDriverOptions = new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true); - public const string RequiresIncrementalSyntaxTreeModifySupport = "The GeneratorDriver treats all SyntaxTree replace operations on a Compilation as an Add/Remove operation instead of a Modify operation" - + ", so all cached results based on that input are thrown out. As a result, we cannot validate that unrelated changes within the same SyntaxTree do not cause regeneration."; - [Fact] public async Task AddingNewUnrelatedType_DoesNotRegenerateSource() { - string source = CodeSnippets.BasicParametersAndModifiers(); + string source = RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers()); Compilation comp1 = await TestUtils.CreateCompilation(source); @@ -52,7 +52,7 @@ public async Task AppendingUnrelatedSource_DoesNotRegenerateSource() string source = $$""" namespace NS { - {{CodeSnippets.BasicParametersAndModifiers()}} + {{RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers())}} } """; @@ -83,7 +83,7 @@ namespace NS [Fact] public async Task AddingFileWithNewLibraryImport_DoesNotRegenerateOriginalMethod() { - string source = CodeSnippets.BasicParametersAndModifiers(); + string source = RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers()); Compilation comp1 = await TestUtils.CreateCompilation(source); @@ -92,7 +92,7 @@ public async Task AddingFileWithNewLibraryImport_DoesNotRegenerateOriginalMethod driver = driver.RunGenerators(comp1); - Compilation comp2 = comp1.AddSyntaxTrees(CSharpSyntaxTree.ParseText(CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.I1), new CSharpParseOptions(LanguageVersion.Preview))); + Compilation comp2 = comp1.AddSyntaxTrees(CSharpSyntaxTree.ParseText(RemoveTestMarkup(CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.I1)), new CSharpParseOptions(LanguageVersion.Preview))); GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; @@ -113,14 +113,14 @@ public async Task AddingFileWithNewLibraryImport_DoesNotRegenerateOriginalMethod [Fact] public async Task ReplacingFileWithNewLibraryImport_DoesNotRegenerateStubsInOtherFiles() { - Compilation comp1 = await TestUtils.CreateCompilation(new string[] { CodeSnippets.BasicParametersAndModifiers(), CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.I1) }); + Compilation comp1 = await TestUtils.CreateCompilation(new string[] { RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers()), RemoveTestMarkup(CodeSnippets.MarshalAsParametersAndModifiers(UnmanagedType.I1)) }); Microsoft.Interop.LibraryImportGenerator generator = new(); GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions); driver = driver.RunGenerators(comp1); - Compilation comp2 = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), CSharpSyntaxTree.ParseText(CodeSnippets.BasicParametersAndModifiers(), new CSharpParseOptions(LanguageVersion.Preview))); + Compilation comp2 = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), CSharpSyntaxTree.ParseText(RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers()), new CSharpParseOptions(LanguageVersion.Preview))); GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; @@ -140,7 +140,7 @@ public async Task ReplacingFileWithNewLibraryImport_DoesNotRegenerateStubsInOthe [Fact] public async Task ChangingMarshallingStrategy_RegeneratesStub() { - string stubSource = CodeSnippets.BasicParametersAndModifiers("CustomType", CodeSnippets.DisableRuntimeMarshalling); + string stubSource = RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers("CustomType", CodeSnippets.DisableRuntimeMarshalling)); string customTypeImpl1 = "struct CustomType { System.IntPtr handle; }"; @@ -179,7 +179,7 @@ public async Task ChangingMarshallingStrategy_RegeneratesStub() [Fact] public async Task ChangingMarshallingAttributes_SameStrategy_DoesNotRegenerate() { - string source = CodeSnippets.BasicParametersAndModifiers(); + string source = RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers()); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)); @@ -192,7 +192,7 @@ public async Task ChangingMarshallingAttributes_SameStrategy_DoesNotRegenerate() SyntaxTree newTree = syntaxTree.WithRootAndOptions( SyntaxFactory.ParseCompilationUnit( - CodeSnippets.MarshalAsParametersAndModifiers(System.Runtime.InteropServices.UnmanagedType.I4)), + RemoveTestMarkup(CodeSnippets.MarshalAsParametersAndModifiers(System.Runtime.InteropServices.UnmanagedType.I4))), syntaxTree.Options); Compilation comp2 = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), newTree); @@ -218,9 +218,9 @@ public async Task ChangingMarshallingAttributes_SameStrategy_DoesNotRegenerate() public static IEnumerable CompilationObjectLivenessSources() { // Basic stub - yield return new[] { CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { RemoveTestMarkup(CodeSnippets.BasicParametersAndModifiers()) }; // Stub with custom string marshaller - yield return new[] { CodeSnippets.CustomStringMarshallingParametersAndModifiers() }; + yield return new[] { RemoveTestMarkup(CodeSnippets.CustomStringMarshallingParametersAndModifiers()) }; } // This test requires precise GC to ensure that we're accurately testing that we aren't @@ -271,5 +271,11 @@ public async Task GeneratorRun_WithNewCompilation_DoesNotKeepOldCompilationAlive return (new WeakReference(comp2), driver2); } } + + private static string RemoveTestMarkup(string sourceWithMarkup) + { + TestFileMarkupParser.GetSpans(sourceWithMarkup, out string sourceWithoutMarkup, out ImmutableArray _); + return sourceWithoutMarkup; + } } } From 7cd20736862a1f24004ed4d63a7824a34463b676 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 18 Apr 2023 16:13:44 -0700 Subject: [PATCH 14/17] Fix multiple sources test. --- .../LibraryImportGenerator.UnitTests/Compiles.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 4b74eda196aba..0847e27e53f83 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -673,7 +673,16 @@ public static IEnumerable CodeSnippetsToCompileMultipleSources() public async Task ValidateSnippetsWithMultipleSources(string id, string[] sources) { TestUtils.Use(id); - await VerifyCS.VerifySourceGeneratorAsync(sources); + // To enable us to reuse snippets that have markup locations in our multiple-sources test, we'll strip out the markup locations. + // We need to do this as each snippet expects to be able to define all expected markup locations (starting from 0), so including multiple snippets + // results in multiple definitions for the same location (which doesn't work). Since we expect no diagnostics, we can strip out the locations. + await VerifyCS.VerifySourceGeneratorAsync(sources.Select(RemoveTestMarkup).ToArray()); + } + + private static string RemoveTestMarkup(string sourceWithMarkup) + { + TestFileMarkupParser.GetSpans(sourceWithMarkup, out string sourceWithoutMarkup, out ImmutableArray _); + return sourceWithoutMarkup; } public static IEnumerable CodeSnippetsToVerifyNoTreesProduced() From c83364d57175ae03762316ce6ab25e135ee260cc Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 21 Apr 2023 11:52:34 -0700 Subject: [PATCH 15/17] Add ActiveIssue for known failures on Mono that these tests now hit --- .../AddDisableRuntimeMarshallingAttributeFixerTests.cs | 1 + 1 file changed, 1 insertion(+) 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 92a6aab6b177b..c93cd35229d71 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/AddDisableRuntimeMarshallingAttributeFixerTests.cs @@ -16,6 +16,7 @@ namespace LibraryImportGenerator.UnitTests { + [ActiveIssue("https://github.com/dotnet/runtime/issues/60650", TestRuntimes.Mono)] public class AddDisableRuntimeMarshallingAttributeFixerTests { [Fact] From 19b5c9351b858ea567aa5beac679ea18ff2700bc Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 4 May 2023 11:43:29 -0700 Subject: [PATCH 16/17] Undo change that shouldnt be in this branch --- .../GenerateUnmanagedEntryPoints.csproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tests/nativeaot/GenerateUnmanagedEntryPoints/GenerateUnmanagedEntryPoints.csproj b/src/tests/nativeaot/GenerateUnmanagedEntryPoints/GenerateUnmanagedEntryPoints.csproj index e2a1107993f8a..db5f0741f8d41 100644 --- a/src/tests/nativeaot/GenerateUnmanagedEntryPoints/GenerateUnmanagedEntryPoints.csproj +++ b/src/tests/nativeaot/GenerateUnmanagedEntryPoints/GenerateUnmanagedEntryPoints.csproj @@ -4,11 +4,6 @@ BuildAndRun true true - - true From 18a8bb05dffdb4ad34294d6ed1d8b869700855e3 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 4 May 2023 13:36:06 -0700 Subject: [PATCH 17/17] Fix error messages in ComInterfaceGenerator tests. --- .../ComInterfaceGenerator.Unit.Tests/CompileFails.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) 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 2272e4782152d..e4db5b789ec8a 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 @@ -64,16 +64,14 @@ public static IEnumerable InvalidUnmanagedToManagedCodeSnippetsToCompi // SafeHandles yield return new object[] { ID(), codeSnippets.BasicParametersAndModifiers("Microsoft.Win32.SafeHandles.SafeFileHandle"), new[] { - // /0/Test0.cs(13,48): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method 'Method'. - VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupported).WithLocation(0).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "Method"), - // /0/Test0.cs(13,98): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'value'. - VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(1).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "value"), + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails).WithLocation(0).WithArguments("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type 'global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller' does not support it.", "Method"), + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails).WithLocation(1).WithArguments("The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type 'global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller' does not support it.", "value"), // /0/Test0.cs(13,151): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'inValue'. - VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(2).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "inValue"), + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails).WithLocation(2).WithArguments("The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type 'global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller' does not support it.", "inValue"), // /0/Test0.cs(13,207): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'refValue'. - VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(3).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "refValue"), + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails).WithLocation(3).WithArguments("The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type 'global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller' does not support it.", "refValue"), // /0/Test0.cs(13,264): error SYSLIB1051: The type 'Microsoft.Win32.SafeHandles.SafeFileHandle' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'outValue'. - VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupported).WithLocation(4).WithArguments("Microsoft.Win32.SafeHandles.SafeFileHandle", "outValue"), + VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails).WithLocation(4).WithArguments("The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type 'global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller' does not support it.", "outValue"), } };