Skip to content

Commit

Permalink
LibraryImport generator AllowUnsafeBlocks diagnostic (dotnet#72650)
Browse files Browse the repository at this point in the history
* LibraryImport generator AllowUnsafeBlocks diagnostic
  • Loading branch information
AaronRobinsonMSFT authored Jul 23, 2022
1 parent 4735fd7 commit 1e1e86d
Show file tree
Hide file tree
Showing 21 changed files with 300 additions and 12 deletions.
11 changes: 8 additions & 3 deletions docs/project/list-of-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,14 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
| __`SYSLIB1059`__ | Marshaller type does not support allocating constructor |
| __`SYSLIB1060`__ | BufferSize should be set on CustomTypeMarshallerAttribute |
| __`SYSLIB1061`__ | Marshaller type has incompatible method signatures |
| __`SYSLIB1062`__ | *_`SYSLIB1062`-`SYSLIB1064` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1063`__ | *_`SYSLIB1062`-`SYSLIB1064` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1064`__ | *_`SYSLIB1062`-`SYSLIB1064` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1062`__ | Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' |
| __`SYSLIB1063`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1064`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1065`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1066`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1067`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1068`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1069`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |

### Diagnostic Suppressions (`SYSLIBSUPPRESS****`)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ public class GeneratorDiagnostics : IGeneratorDiagnostics
{
public class Ids
{
// SYSLIB1050-SYSLIB1059 are reserved for LibraryImportGenerator
// SYSLIB1050-SYSLIB1069 are reserved for LibraryImportGenerator
public const string Prefix = "SYSLIB";
public const string InvalidLibraryImportAttributeUsage = Prefix + "1050";
public const string TypeNotSupported = Prefix + "1051";
public const string ConfigurationNotSupported = Prefix + "1052";
public const string CannotForwardToDllImport = Prefix + "1053";

public const string RequiresAllowUnsafeBlocks = Prefix + "1062";
}

private const string Category = "LibraryImportGenerator";
Expand Down Expand Up @@ -157,6 +159,16 @@ public class Ids
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.CannotForwardToDllImportDescription)));

public static readonly DiagnosticDescriptor RequiresAllowUnsafeBlocks =
new DiagnosticDescriptor(
Ids.RequiresAllowUnsafeBlocks,
GetResourceString(nameof(SR.RequiresAllowUnsafeBlocksTitle)),
GetResourceString(nameof(SR.RequiresAllowUnsafeBlocksMessage)),
Category,
DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.RequiresAllowUnsafeBlocksDescription)));

private readonly List<Diagnostic> _diagnostics = new List<Diagnostic>();

public IEnumerable<Diagnostic> Diagnostics => _diagnostics;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public static class StepNames

public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Collect all methods adorned with LibraryImportAttribute
var attributedMethods = context.SyntaxProvider
.ForAttributeWithMetadataName(
context,
Expand All @@ -72,6 +73,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Where(
static modelData => modelData is not null);

// Validate if attributed methods can have source generated
var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) =>
{
Diagnostic? diagnostic = GetDiagnosticIfInvalidMethodForGeneration(data.Syntax, data.Symbol);
Expand All @@ -81,16 +83,33 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var methodsToGenerate = methodsWithDiagnostics.Where(static data => data.Diagnostic is null);
var invalidMethodDiagnostics = methodsWithDiagnostics.Where(static data => data.Diagnostic is not null);

// Report diagnostics for invalid methods
context.RegisterSourceOutput(invalidMethodDiagnostics, static (context, invalidMethod) =>
{
context.ReportDiagnostic(invalidMethod.Diagnostic);
});

// Compute generator options
IncrementalValueProvider<LibraryImportGeneratorOptions> stubOptions = context.AnalyzerConfigOptionsProvider
.Select(static (options, ct) => new LibraryImportGeneratorOptions(options.GlobalOptions));

IncrementalValueProvider<StubEnvironment> stubEnvironment = context.CreateStubEnvironmentProvider();

// Validate environment that is being used to generate stubs.
context.RegisterDiagnostics(stubEnvironment.Combine(attributedMethods.Collect()).SelectMany((data, ct) =>
{
if (data.Right.IsEmpty // no attributed methods
|| data.Left.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true } // Unsafe code enabled
|| data.Left.TargetFramework != TargetFramework.Net) // Non-.NET 5 scenarios use forwarders and don't need unsafe code
{
return ImmutableArray<Diagnostic>.Empty;
}

return ImmutableArray.Create(Diagnostic.Create(GeneratorDiagnostics.RequiresAllowUnsafeBlocks, null));
}));

IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateSingleStub = methodsToGenerate
.Combine(context.CreateStubEnvironmentProvider())
.Combine(stubEnvironment)
.Combine(stubOptions)
.Select(static (data, ct) => new
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,13 @@
<data name="MarshallerTypeMustBeNonNullMessage" xml:space="preserve">
<value>The 'marshallerType' parameter in the 'System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute' cannot be 'null'</value>
</data>
<data name="RequiresAllowUnsafeBlocksDescription" xml:space="preserve">
<value>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</value>
</data>
<data name="RequiresAllowUnsafeBlocksMessage" xml:space="preserve">
<value>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</value>
</data>
<data name="RequiresAllowUnsafeBlocksTitle" xml:space="preserve">
<value>LibraryImportAttribute requires unsafe code.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
<target state="new">The marshaller type '{0}' for managed type '{1}' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksDescription">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksMessage">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksTitle">
<source>LibraryImportAttribute requires unsafe code.</source>
<target state="new">LibraryImportAttribute requires unsafe code.</target>
<note />
</trans-unit>
<trans-unit id="ToUnmanagedFromManagedTypesMustMatchDescription">
<source>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</source>
<target state="new">The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
<target state="new">The marshaller type '{0}' for managed type '{1}' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksDescription">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksMessage">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksTitle">
<source>LibraryImportAttribute requires unsafe code.</source>
<target state="new">LibraryImportAttribute requires unsafe code.</target>
<note />
</trans-unit>
<trans-unit id="ToUnmanagedFromManagedTypesMustMatchDescription">
<source>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</source>
<target state="new">The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
<target state="new">The marshaller type '{0}' for managed type '{1}' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksDescription">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksMessage">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksTitle">
<source>LibraryImportAttribute requires unsafe code.</source>
<target state="new">LibraryImportAttribute requires unsafe code.</target>
<note />
</trans-unit>
<trans-unit id="ToUnmanagedFromManagedTypesMustMatchDescription">
<source>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</source>
<target state="new">The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
<target state="new">The marshaller type '{0}' for managed type '{1}' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksDescription">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksMessage">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksTitle">
<source>LibraryImportAttribute requires unsafe code.</source>
<target state="new">LibraryImportAttribute requires unsafe code.</target>
<note />
</trans-unit>
<trans-unit id="ToUnmanagedFromManagedTypesMustMatchDescription">
<source>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</source>
<target state="new">The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
<target state="new">The marshaller type '{0}' for managed type '{1}' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksDescription">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksMessage">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksTitle">
<source>LibraryImportAttribute requires unsafe code.</source>
<target state="new">LibraryImportAttribute requires unsafe code.</target>
<note />
</trans-unit>
<trans-unit id="ToUnmanagedFromManagedTypesMustMatchDescription">
<source>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</source>
<target state="new">The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
<target state="new">The marshaller type '{0}' for managed type '{1}' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksDescription">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksMessage">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksTitle">
<source>LibraryImportAttribute requires unsafe code.</source>
<target state="new">LibraryImportAttribute requires unsafe code.</target>
<note />
</trans-unit>
<trans-unit id="ToUnmanagedFromManagedTypesMustMatchDescription">
<source>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</source>
<target state="new">The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,21 @@
<target state="new">The marshaller type '{0}' for managed type '{1}' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksDescription">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksMessage">
<source>LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</source>
<target state="new">LibraryImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</target>
<note />
</trans-unit>
<trans-unit id="RequiresAllowUnsafeBlocksTitle">
<source>LibraryImportAttribute requires unsafe code.</source>
<target state="new">LibraryImportAttribute requires unsafe code.</target>
<note />
</trans-unit>
<trans-unit id="ToUnmanagedFromManagedTypesMustMatchDescription">
<source>The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</source>
<target state="new">The return type of 'ConvertToUnmanaged' and the parameter type of 'ConvertToManaged' must be the same.</target>
Expand Down
Loading

0 comments on commit 1e1e86d

Please sign in to comment.