diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshalling.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshalling.cs index 4a1d45ba89..99010ef05c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshalling.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshalling.cs @@ -149,7 +149,7 @@ public override void Initialize(AnalysisContext context) var disabledRuntimeMarshallingAssemblyAnalyzer = new DisabledRuntimeMarshallingAssemblyAnalyzer(context.Compilation, autoLayoutCache); disabledRuntimeMarshallingAssemblyAnalyzer.RegisterActions(context); } - var delegateInteropUsageAnalyzer = new DelegateInteropUsageAnalyzer(context.Compilation, autoLayoutCache); + var delegateInteropUsageAnalyzer = new DelegateInteropUsageAnalyzer(context.Compilation, autoLayoutCache, disableRuntimeMarshallingAttribute); delegateInteropUsageAnalyzer.RegisterActions(context, hasDisableRuntimeMarshallingAttribute); } }); diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingAnalyzer.DelegateInteropUsageAnalyzer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingAnalyzer.DelegateInteropUsageAnalyzer.cs index 8df60a6266..d66b0a08ff 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingAnalyzer.DelegateInteropUsageAnalyzer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingAnalyzer.DelegateInteropUsageAnalyzer.cs @@ -20,8 +20,9 @@ private sealed class DelegateInteropUsageAnalyzer private readonly IMethodSymbol? _getFunctionPointerForDelegateNonGeneric; private readonly IMethodSymbol? _getFunctionPointerForDelegateGeneric; private readonly AutoLayoutTypeCache _autoLayoutCache; + private readonly INamedTypeSymbol _disableRuntimeMarshallingAttribute; - public DelegateInteropUsageAnalyzer(Compilation compilation, AutoLayoutTypeCache autoLayoutCache) + public DelegateInteropUsageAnalyzer(Compilation compilation, AutoLayoutTypeCache autoLayoutCache, INamedTypeSymbol disableRuntimeMarshallingAttribute) { if (compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesMarshal, out var marshalType)) { @@ -34,6 +35,7 @@ public DelegateInteropUsageAnalyzer(Compilation compilation, AutoLayoutTypeCache } _autoLayoutCache = autoLayoutCache; + _disableRuntimeMarshallingAttribute = disableRuntimeMarshallingAttribute; } public void RegisterActions(CompilationStartAnalysisContext context, bool hasDisableRuntimeMarshallingAttribute) @@ -88,7 +90,10 @@ private void AnalyzeInvocation(OperationAnalysisContext context) void AnalyzeDelegateType(OperationAnalysisContext context, IOperation operation, INamedTypeSymbol delegateType) { - AnalyzeMethodSignature(_autoLayoutCache, context.ReportDiagnostic, delegateType.DelegateInvokeMethod, ImmutableArray.Create(operation.Syntax.GetLocation()), FeatureUnsupportedWhenRuntimeMarshallingDisabledDelegateUsage); + if (delegateType.ContainingAssembly.HasAttribute(_disableRuntimeMarshallingAttribute)) + { + AnalyzeMethodSignature(_autoLayoutCache, context.ReportDiagnostic, delegateType.DelegateInvokeMethod, ImmutableArray.Create(operation.Syntax.GetLocation()), FeatureUnsupportedWhenRuntimeMarshallingDisabledDelegateUsage); + } } } @@ -132,7 +137,10 @@ private void AnalyzeMethod(Action reportDiagnostic, IMethodSymbol sy void AnalyzeDelegateMethodSignature(INamedTypeSymbol delegateType, ISymbol signatureSymbol) { - AnalyzeMethodSignature(_autoLayoutCache, reportDiagnostic, delegateType.DelegateInvokeMethod, signatureSymbol.Locations, FeatureUnsupportedWhenRuntimeMarshallingDisabledDelegateUsage); + if (delegateType.ContainingAssembly.HasAttribute(_disableRuntimeMarshallingAttribute)) + { + AnalyzeMethodSignature(_autoLayoutCache, reportDiagnostic, delegateType.DelegateInvokeMethod, signatureSymbol.Locations, FeatureUnsupportedWhenRuntimeMarshallingDisabledDelegateUsage); + } } } } diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingTests.cs index e352948ed1..011df8a78c 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/DisableRuntimeMarshallingTests.cs @@ -803,6 +803,55 @@ class C await VerifyCSAnalyzerWithAdditionalAssemblyAsync(source, delegateDefinition); } + [Fact] + [WorkItem(6094, "https://github.com/dotnet/roslyn-analyzers/issues/6094")] + public async Task CS_DelegateWith_NonBlittableParameter_PInvokeUsage_NoDisableRuntimeMarshalling_DoesNotEmit_Diagnostic() + { + string source = @" +using System; +using System.Runtime.InteropServices; + +internal delegate void DelegateType(string[] str); + +class C +{ + [DllImport(""Native"")] + public static extern void PInvoke(DelegateType d); + [DllImport(""Native"")] + public static extern DelegateType PInvoke(); + [DllImport(""Native"")] + public static extern void PInvokeArray(DelegateType[] d); + [DllImport(""Native"")] + public static extern DelegateType[] PInvokeArray(); +} +"; + await VerifyCSAnalyzerAsync(source); + } + + [Fact] + [WorkItem(6094, "https://github.com/dotnet/roslyn-analyzers/issues/5995")] + public async Task CS_DelegateWithClassReturnValue_NoUnmanagedFunctionPointer_MarshalAPIUsage_NoDisableRuntimeMarshalling_DoesNotEmit_Diagnostic() + { + string source = @" +using System; +using System.Runtime.InteropServices; + +public delegate string DelegateType(); + +class C +{ + public static void M(DelegateType d, IntPtr i) + { + _ = Marshal.GetFunctionPointerForDelegate((Delegate)d); + _ = Marshal.GetFunctionPointerForDelegate(d); + _ = Marshal.GetDelegateForFunctionPointer(i, typeof(DelegateType)); + _ = Marshal.GetDelegateForFunctionPointer(i); + } +} +"; + await VerifyCSAnalyzerAsync(source); + } + [Fact] public async Task VB_DelegateWithClassReturnValue_Emits_Diagnostic() {