Skip to content

Commit

Permalink
Block "Convert To LibraryImport" in more unsupported cases (#87503)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Jun 22, 2023
1 parent 9955370 commit 2a09527
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,24 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
if (dllImportData == null)
return;

if (dllImportData.ThrowOnUnmappableCharacter == true)
{
// LibraryImportGenerator doesn't support ThrowOnUnmappableCharacter = true
return;
}

// LibraryImportGenerator doesn't support BestFitMapping = true
if (IsBestFitMapping(method, dllImportData))
{
return;
}

if (method.IsVararg)
{
// LibraryImportGenerator doesn't support varargs
return;
}

// Ignore methods already marked LibraryImport
// This can be the case when the generator creates an extern partial function for blittable signatures.
foreach (AttributeData attr in method.GetAttributes())
Expand Down Expand Up @@ -139,6 +157,28 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
context.ReportDiagnostic(method.CreateDiagnosticInfo(ConvertToLibraryImport, properties.ToImmutable(), method.Name).ToDiagnostic());
}

private static bool IsBestFitMapping(IMethodSymbol method, DllImportData? dllImportData)
{
if (dllImportData.BestFitMapping.HasValue)
{
return dllImportData.BestFitMapping.Value;
}

AttributeData? bestFitMappingContainingType = method.ContainingType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_InteropServices_BestFitMappingAttribute);
if (bestFitMappingContainingType is not null)
{
return bestFitMappingContainingType.ConstructorArguments[0].Value is true;
}

AttributeData? bestFitMappingContainingAssembly = method.ContainingAssembly.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_InteropServices_BestFitMappingAttribute);
if (bestFitMappingContainingAssembly is not null)
{
return bestFitMappingContainingAssembly.ConstructorArguments[0].Value is true;
}

return false;
}

private static bool HasUnsupportedMarshalAsInfo(TypePositionInfo info)
{
if (info.MarshallingAttributeInfo is not MarshalAsInfo(UnmanagedType unmanagedType, _))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,7 @@ public static string MarshalEx(InteropGenerationOptions options)
public const string System_Runtime_InteropServices_Marshalling_ComInterfaceMarshaller_Metadata = "System.Runtime.InteropServices.Marshalling.ComInterfaceMarshaller`1";

public const string System_Runtime_InteropServices_Marshalling_ComObject = "System.Runtime.InteropServices.Marshalling.ComObject";

public const string System_Runtime_InteropServices_BestFitMappingAttribute = "System.Runtime.InteropServices.BestFitMappingAttribute";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,114 @@ unsafe partial class Test
public static extern {{typeName}} {|#1:Method_Return|}();
}
""";

[Fact]
public async Task BestFitMapping_True_NoDiagnostic()
{
string source = """
using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", BestFitMapping = true)]
public static extern void Method2();
}
""";
await VerifyCS.VerifyAnalyzerAsync(source);
}

[Fact]
public async Task ThrowOnUnmappableChar_True_NoDiagnostic()
{
string source = """
using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", ThrowOnUnmappableChar = true)]
public static extern void Method2();
}
""";
await VerifyCS.VerifyAnalyzerAsync(source);
}

[Fact]
public async Task BestFitMapping_Assembly_True_NoDiagnostic()
{
string source = """
using System.Runtime.InteropServices;
[assembly:BestFitMapping(true)]
partial class Test
{
[DllImport("DoesNotExist")]
public static extern void Method2();
}
""";
await VerifyCS.VerifyAnalyzerAsync(source);
}

[Fact]
public async Task BestFitMapping_Type_True_NoDiagnostic()
{
string source = """
using System.Runtime.InteropServices;
[BestFitMapping(true)]
partial class Test
{
[DllImport("DoesNotExist")]
public static extern void Method2();
}
""";
await VerifyCS.VerifyAnalyzerAsync(source);
}

[Fact]
public async Task BestFitMapping_Assembly_False_Diagnostic()
{
string source = """
using System.Runtime.InteropServices;
[assembly:BestFitMapping(false)]
partial class Test
{
[DllImport("DoesNotExist")]
public static extern void [|Method2|]();
}
""";
await VerifyCS.VerifyAnalyzerAsync(source);
}

[Fact]
public async Task BestFitMapping_Type_False_Diagnostic()
{
string source = """
using System.Runtime.InteropServices;
[BestFitMapping(false)]
partial class Test
{
[DllImport("DoesNotExist")]
public static extern void [|Method2|]();
}
""";
await VerifyCS.VerifyAnalyzerAsync(source);
}

[Fact]
public async Task Varargs_NoDiagnostic()
{
string source = """
using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist")]
public static extern void Method2(__arglist);
}
""";
await VerifyCS.VerifyAnalyzerAsync(source);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,58 @@ await VerifyCodeFixAsync(
new Dictionary<string, Option> { { Option.MayRequireAdditionalWork, new Option.Bool(true) } });
}

[Fact]
public async Task BestFitMappingExplicitFalse()
{
string source = """
using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", BestFitMapping = false)]
public static extern void [|Method|]();
}
""";

string fixedSource = """
using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist")]
public static partial void {|CS8795:Method|}();
}
""";

await VerifyCodeFixAsync(source, fixedSource);
}

[Fact]
public async Task ThrowOnUnmappableCharExplicitFalse()
{
string source = """
using System.Runtime.InteropServices;
partial class Test
{
[DllImport("DoesNotExist", ThrowOnUnmappableChar = false)]
public static extern void [|Method|]();
}
""";

string fixedSource = """
using System.Runtime.InteropServices;
partial class Test
{
[LibraryImport("DoesNotExist")]
public static partial void {|CS8795:Method|}();
}
""";

await VerifyCodeFixAsync(source, fixedSource);
}

private static async Task VerifyCodeFixAsync(string source, string fixedSource)
{
var test = new VerifyCS.Test
Expand Down

0 comments on commit 2a09527

Please sign in to comment.