Skip to content

Commit

Permalink
Disable the "casts between generated and built-in COM interop" analyz…
Browse files Browse the repository at this point in the history
…er when the "enable interop between generated COM interop and built-in COM interop" feature is enabled. (#89125)
  • Loading branch information
jkoritzinsky committed Jul 19, 2023
1 parent 5864743 commit c430570
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,17 @@ public override void Initialize(AnalysisContext context)
}
}, OperationKind.Invocation);
bool enableGeneratedComInterfaceComImportInterop = context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue("build_property.EnableGeneratedComInterfaceComImportInterop", out string enableSourceGeneratedBuiltInInteropOption)
&& bool.TryParse(enableSourceGeneratedBuiltInInteropOption, out bool enableSourceGeneratedBuiltInInterop)
&& enableSourceGeneratedBuiltInInterop;
var getObjectForIUnknown = marshalType.GetMembers("GetObjectForIUnknown")[0];
context.RegisterOperationAction(context =>
{
var operation = (IConversionOperation)context.Operation;
if (operation.Type is INamedTypeSymbol { IsComImport: true })
if (operation.Type is INamedTypeSymbol { IsComImport: true } && !enableGeneratedComInterfaceComImportInterop)
{
IOperation operand = operation.Operand;
if (operand is IConversionOperation { Type.SpecialType: SpecialType.System_Object } objConversion)
Expand Down Expand Up @@ -171,7 +175,7 @@ public override void Initialize(AnalysisContext context)
{
operand = objConversion.Operand;
}
if (operand.Type is INamedTypeSymbol { IsComImport: true })
if (operand.Type is INamedTypeSymbol { IsComImport: true } && !enableGeneratedComInterfaceComImportInterop)
{
context.ReportDiagnostic(
Diagnostic.Create(
Expand All @@ -181,6 +185,8 @@ public override void Initialize(AnalysisContext context)
}
else if (operand is IInvocationOperation invocation && invocation.TargetMethod.Equals(getObjectForIUnknown, SymbolEqualityComparer.Default))
{
// The returned value from Marshal.GetObjectForIUnknown will always be a built-in COM object, which can't be cast to a source-generated COM type,
// even with the interop feature enabled.
context.ReportDiagnostic(
Diagnostic.Create(
CastsBetweenRuntimeComAndSourceGeneratedComNotSupported,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,6 @@ public static void Foo(ComObject c)
await VerifyAnalyzerAsync(source);
}



[Fact]
public async Task GetObjectForIUnknown()
{
Expand Down Expand Up @@ -508,6 +506,87 @@ public static void Foo(nint i)
await VerifyAnalyzerAsync(source);
}

[Fact]
public async Task CastsBetweenComImportAndGeneratedComTypes_InteropEnabled_NoDiagnostic()
{
string source = """
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

[GeneratedComInterface]
[Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")]
public interface I
{
}

[GeneratedComClass]
public class C : I
{
}

[ComImport]
[Guid("0BADBF92-749A-44DB-9DA0-C8E2EEC783E2")]
public interface J
{
}

public static class Program
{
public static void Foo(I i)
{
J j = (J)i;
i = (I)j;
}

public static void Foo(C c)
{
J j = (J)c;
c = (C)j;
}

public static void Foo(ComObject c)
{
J j = (J)(object)c;
c = (ComObject)(object)j;
}
}
""";

await VerifyAnalyzerInteropEnabledAsync(source);
}

[Fact]
public async Task GetObjectForIUnknown_ReportsDiagnostic()
{
string source = """
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

[GeneratedComInterface]
[Guid("0B7171CD-04A3-41B6-AD10-FE86D52197DD")]
public interface I
{
}

[GeneratedComClass]
public class C : I
{
}

public static class Program
{
public static void Foo(nint i)
{
I io = [|(I)Marshal.GetObjectForIUnknown(i)|];
C co = [|(C)Marshal.GetObjectForIUnknown(i)|];
ComObject obj = [|(ComObject)Marshal.GetObjectForIUnknown(i)|];
}
}
""";

await VerifyAnalyzerInteropEnabledAsync(source);
}

[Fact]
public async Task SetNullToComImportField()
{
Expand Down Expand Up @@ -540,5 +619,29 @@ private Task VerifyAnalyzerAsync(string source)

return test.RunAsync(CancellationToken.None);
}

private Task VerifyAnalyzerInteropEnabledAsync(string source)
{
var test = new VerifyCS.Test
{
MarkupOptions = Microsoft.CodeAnalysis.Testing.MarkupOptions.UseFirstDescriptor,
TestState =
{
Sources =
{
source,
},
AnalyzerConfigFiles =
{
("/.editorconfig", """
is_global = true
build_property.EnableGeneratedComInterfaceComImportInterop = true
""")
}
}
};

return test.RunAsync(CancellationToken.None);
}
}
}

0 comments on commit c430570

Please sign in to comment.