| __`SYSLIB1067`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1068`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
| __`SYSLIB1069`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
+| __`SYSLIB1070`__ | Invalid 'JSImportAttribute' usage |
+| __`SYSLIB1071`__ | Invalid 'JSExportAttribute' usage |
+| __`SYSLIB1072`__ | Specified type is not supported by source-generated JavaScript interop |
+| __`SYSLIB1073`__ | Specified configuration is not supported by source-generated JavaScript interop |
+| __`SYSLIB1074`__ | JSImportAttribute requires unsafe code |
+| __`SYSLIB1075`__ | JSExportAttribute requires unsafe code |
+| __`SYSLIB1076`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
+| __`SYSLIB1077`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
+| __`SYSLIB1078`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
+| __`SYSLIB1079`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
+| __`SYSLIB1080`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
+
### Diagnostic Suppressions (`SYSLIBSUPPRESS****`)
<Compile Include="System\Runtime\InteropServices\JavaScript\Http\HttpRequestMessageTest.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\ParallelTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\TimerTests.cs" />
- <Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\tests\System\Runtime\InteropServices\JavaScript\Utils.cs" Link="System\Runtime\InteropServices\JavaScript\Utils.cs" />
+ <Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\tests\System.Runtime.InteropServices.JavaScript.UnitTests\System\Runtime\InteropServices\JavaScript\Utils.cs" Link="System\Runtime\InteropServices\JavaScript\Utils.cs" />
</ItemGroup>
<ItemGroup>
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JSImportGenerator.Unit.Tests", "tests\JSImportGenerator.UnitTest\JSImportGenerator.Unit.Tests.csproj", "{BFED925C-18F2-4C98-833E-66F205234598}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices.JavaScript.Tests", "tests\System.Runtime.InteropServices.JavaScript.Tests.csproj", "{765B4AA5-723A-44FF-BC4E-EB0F03103F6D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices.JavaScript.Tests", "tests\System.Runtime.InteropServices.JavaScript.UnitTests\System.Runtime.InteropServices.JavaScript.Tests.csproj", "{765B4AA5-723A-44FF-BC4E-EB0F03103F6D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{09AA6758-0BD3-4312-9C07-AE9F1D50A3AD}"
EndProject
{
public class Ids
{
- // SYSLIB1050-SYSLIB1059 are reserved for JSImportGenerator
- public const string Prefix = "JS";
- public const string InvalidJSImportAttributeUsage = Prefix + "1050";
- public const string TypeNotSupported = Prefix + "1051";
- public const string ConfigurationNotSupported = Prefix + "1052";
- public const string CannotForwardToDllImport = Prefix + "1053";
+ // SYSLIB1070-SYSLIB1089 are reserved for JSImportGenerator
+ public const string Prefix = "SYSLIB";
+ public const string InvalidJSImportAttributeUsage = Prefix + "1070";
+ public const string InvalidJSExportAttributeUsage = Prefix + "1071";
+ public const string TypeNotSupported = Prefix + "1072";
+ public const string ConfigurationNotSupported = Prefix + "1073";
+ public const string JSImportRequiresAllowUnsafeBlocks = Prefix + "1074";
+ public const string JSExportRequiresAllowUnsafeBlocks = Prefix + "1075";
}
private const string Category = "JSImportGenerator";
public static readonly DiagnosticDescriptor InvalidExportAttributedMethodSignature =
new DiagnosticDescriptor(
- Ids.InvalidJSImportAttributeUsage,
+ Ids.InvalidJSExportAttributeUsage,
GetResourceString(nameof(SR.InvalidJSExportAttributeUsageTitle)),
GetResourceString(nameof(SR.InvalidJSExportAttributedMethodSignatureMessage)),
Category,
public static readonly DiagnosticDescriptor InvalidExportAttributedMethodContainingTypeMissingModifiers =
new DiagnosticDescriptor(
- Ids.InvalidJSImportAttributeUsage,
- GetResourceString(nameof(SR.InvalidJSImportAttributeUsageTitle)),
+ Ids.InvalidJSExportAttributeUsage,
+ GetResourceString(nameof(SR.InvalidJSExportAttributeUsageTitle)),
GetResourceString(nameof(SR.InvalidAttributedMethodContainingTypeMissingModifiersMessage)),
Category,
DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.InvalidJSExportAttributedMethodDescription)));
+ public static readonly DiagnosticDescriptor JSImportRequiresAllowUnsafeBlocks =
+ new DiagnosticDescriptor(
+ Ids.JSImportRequiresAllowUnsafeBlocks,
+ GetResourceString(nameof(SR.JSImportRequiresAllowUnsafeBlocksTitle)),
+ GetResourceString(nameof(SR.JSImportRequiresAllowUnsafeBlocksMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(SR.JSImportRequiresAllowUnsafeBlocksDescription)));
+
+ public static readonly DiagnosticDescriptor JSExportRequiresAllowUnsafeBlocks =
+ new DiagnosticDescriptor(
+ Ids.JSExportRequiresAllowUnsafeBlocks,
+ GetResourceString(nameof(SR.JSExportRequiresAllowUnsafeBlocksTitle)),
+ GetResourceString(nameof(SR.JSExportRequiresAllowUnsafeBlocksMessage)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(SR.JSExportRequiresAllowUnsafeBlocksDescription)));
+
private static LocalizableResourceString GetResourceString(string resourceName)
{
return new LocalizableResourceString(resourceName, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.JavaScript.JSImportGenerator.SR));
public void Initialize(IncrementalGeneratorInitializationContext context)
{
+ // Collect all methods adorned with JSExportAttribute
var attributedMethods = context.SyntaxProvider
.CreateSyntaxProvider(
static (node, ct) => ShouldVisitNode(node),
.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);
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<JSGeneratorOptions> stubOptions = context.AnalyzerConfigOptionsProvider
.Select(static (options, ct) => new JSGeneratorOptions(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
+ {
+ return ImmutableArray<Diagnostic>.Empty;
+ }
+
+ return ImmutableArray.Create(Diagnostic.Create(GeneratorDiagnostics.JSExportRequiresAllowUnsafeBlocks, null));
+ }));
+
IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateSingleStub = methodsToGenerate
- .Combine(context.CreateStubEnvironmentProvider())
+ .Combine(stubEnvironment)
.Combine(stubOptions)
.Select(static (data, ct) => new
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
+ // Collect all methods adorned with JSImportAttribute
var attributedMethods = context.SyntaxProvider
.CreateSyntaxProvider(
static (node, ct) => ShouldVisitNode(node),
.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);
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<JSGeneratorOptions> stubOptions = context.AnalyzerConfigOptionsProvider
.Select(static (options, ct) => new JSGeneratorOptions(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
+ {
+ return ImmutableArray<Diagnostic>.Empty;
+ }
+
+ return ImmutableArray.Create(Diagnostic.Create(GeneratorDiagnostics.JSImportRequiresAllowUnsafeBlocks, null));
+ }));
+
IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateSingleStub = methodsToGenerate
- .Combine(context.CreateStubEnvironmentProvider())
+ .Combine(stubEnvironment)
.Combine(stubOptions)
.Select(static (data, ct) => new
{
<value>Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of {0}.</value>
<comment>{0} is a type of the argument</comment>
</data>
+ <data name="JSImportRequiresAllowUnsafeBlocksDescription" xml:space="preserve">
+ <value>JSImportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'.</value>
+ </data>
+ <data name="JSImportRequiresAllowUnsafeBlocksMessage" xml:space="preserve">
+ <value>JSImportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'.</value>
+ </data>
+ <data name="JSImportRequiresAllowUnsafeBlocksTitle" xml:space="preserve">
+ <value>JSImportAttribute requires unsafe code.</value>
+ </data>
+ <data name="JSExportRequiresAllowUnsafeBlocksDescription" xml:space="preserve">
+ <value>JSExportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'.</value>
+ </data>
+ <data name="JSExportRequiresAllowUnsafeBlocksMessage" xml:space="preserve">
+ <value>JSExportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'.</value>
+ </data>
+ <data name="JSExportRequiresAllowUnsafeBlocksTitle" xml:space="preserve">
+ <value>JSExportAttribute requires unsafe code.</value>
+ </data>
</root>
\ No newline at end of file
[MemberData(nameof(CodeSnippetsToCompile))]
public async Task ValidateSnippets(string source)
{
- Compilation comp = await TestUtils.CreateCompilation(source);
+ Compilation comp = await TestUtils.CreateCompilation(source, allowUnsafe: true);
TestUtils.AssertPreSourceGeneratorCompilation(comp);
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags,
[MemberData(nameof(CodeSnippetsToFail))]
public async Task ValidateFailSnippets(string source, string[]? generatorMessages, string[]? compilerMessages)
{
- Compilation comp = await TestUtils.CreateCompilation(source);
+ Compilation comp = await TestUtils.CreateCompilation(source, allowUnsafe: true);
TestUtils.AssertPreSourceGeneratorCompilation(comp);
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags,
JSTestUtils.AssertMessages(compilationDiags, compilerMessages);
}
}
+
+ [Fact]
+ public async Task ValidateRequireAllowUnsafeBlocksDiagnostic()
+ {
+ string source = CodeSnippets.TrivialClassDeclarations;
+ Compilation comp = await TestUtils.CreateCompilation(new[] { source }, allowUnsafe: false);
+ TestUtils.AssertPreSourceGeneratorCompilation(comp);
+
+ var newComp = TestUtils.RunGenerators(comp, out var generatorDiags,
+ new Microsoft.Interop.JavaScript.JSImportGenerator(),
+ new Microsoft.Interop.JavaScript.JSExportGenerator());
+
+ // The errors should indicate the AllowUnsafeBlocks is required.
+ Assert.True(generatorDiags.Single(d => d.Id == "SYSLIB1074") != null);
+ Assert.True(generatorDiags.Single(d => d.Id == "SYSLIB1075") != null);
+ }
}
}