Skip to content

Commit 222da17

Browse files
authored
[wasm] JSImport generator AllowUnsafeBlocks diagnostic (dotnet#72996)
- added `JSImportAttribute requires unsafe code` + unit test - fixed Diagnostic IDs + reservation - moved System.Runtime.InteropServices.JavaScript.UnitTests to subfolder
1 parent 992cf8c commit 222da17

File tree

14 files changed

+119
-15
lines changed

14 files changed

+119
-15
lines changed

docs/project/list-of-diagnostics.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,18 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
179179
| __`SYSLIB1067`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
180180
| __`SYSLIB1068`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
181181
| __`SYSLIB1069`__ | *_`SYSLIB1063`-`SYSLIB1069` reserved for Microsoft.Interop.LibraryImportGenerator._* |
182+
| __`SYSLIB1070`__ | Invalid 'JSImportAttribute' usage |
183+
| __`SYSLIB1071`__ | Invalid 'JSExportAttribute' usage |
184+
| __`SYSLIB1072`__ | Specified type is not supported by source-generated JavaScript interop |
185+
| __`SYSLIB1073`__ | Specified configuration is not supported by source-generated JavaScript interop |
186+
| __`SYSLIB1074`__ | JSImportAttribute requires unsafe code |
187+
| __`SYSLIB1075`__ | JSExportAttribute requires unsafe code |
188+
| __`SYSLIB1076`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
189+
| __`SYSLIB1077`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
190+
| __`SYSLIB1078`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
191+
| __`SYSLIB1079`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
192+
| __`SYSLIB1080`__ | *_`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator.* |
193+
182194

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

src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System.Private.Runtime.InteropServices.JavaScript.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<Compile Include="System\Runtime\InteropServices\JavaScript\Http\HttpRequestMessageTest.cs" />
1919
<Compile Include="System\Runtime\InteropServices\JavaScript\ParallelTests.cs" />
2020
<Compile Include="System\Runtime\InteropServices\JavaScript\TimerTests.cs" />
21-
<Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\tests\System\Runtime\InteropServices\JavaScript\Utils.cs" Link="System\Runtime\InteropServices\JavaScript\Utils.cs" />
21+
<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" />
2222
</ItemGroup>
2323

2424
<ItemGroup>

src/libraries/System.Runtime.InteropServices.JavaScript/System.Runtime.InteropServices.JavaScript.sln

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServi
1111
EndProject
1212
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JSImportGenerator.Unit.Tests", "tests\JSImportGenerator.UnitTest\JSImportGenerator.Unit.Tests.csproj", "{BFED925C-18F2-4C98-833E-66F205234598}"
1313
EndProject
14-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices.JavaScript.Tests", "tests\System.Runtime.InteropServices.JavaScript.Tests.csproj", "{765B4AA5-723A-44FF-BC4E-EB0F03103F6D}"
14+
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}"
1515
EndProject
1616
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{09AA6758-0BD3-4312-9C07-AE9F1D50A3AD}"
1717
EndProject

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/GeneratorDiagnostics.cs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ public class GeneratorDiagnostics : IGeneratorDiagnostics
1717
{
1818
public class Ids
1919
{
20-
// SYSLIB1050-SYSLIB1059 are reserved for JSImportGenerator
21-
public const string Prefix = "JS";
22-
public const string InvalidJSImportAttributeUsage = Prefix + "1050";
23-
public const string TypeNotSupported = Prefix + "1051";
24-
public const string ConfigurationNotSupported = Prefix + "1052";
25-
public const string CannotForwardToDllImport = Prefix + "1053";
20+
// SYSLIB1070-SYSLIB1089 are reserved for JSImportGenerator
21+
public const string Prefix = "SYSLIB";
22+
public const string InvalidJSImportAttributeUsage = Prefix + "1070";
23+
public const string InvalidJSExportAttributeUsage = Prefix + "1071";
24+
public const string TypeNotSupported = Prefix + "1072";
25+
public const string ConfigurationNotSupported = Prefix + "1073";
26+
public const string JSImportRequiresAllowUnsafeBlocks = Prefix + "1074";
27+
public const string JSExportRequiresAllowUnsafeBlocks = Prefix + "1075";
2628
}
2729

2830
private const string Category = "JSImportGenerator";
@@ -268,7 +270,7 @@ public void ReportMarshallingNotSupported(
268270

269271
public static readonly DiagnosticDescriptor InvalidExportAttributedMethodSignature =
270272
new DiagnosticDescriptor(
271-
Ids.InvalidJSImportAttributeUsage,
273+
Ids.InvalidJSExportAttributeUsage,
272274
GetResourceString(nameof(SR.InvalidJSExportAttributeUsageTitle)),
273275
GetResourceString(nameof(SR.InvalidJSExportAttributedMethodSignatureMessage)),
274276
Category,
@@ -288,14 +290,34 @@ public void ReportMarshallingNotSupported(
288290

289291
public static readonly DiagnosticDescriptor InvalidExportAttributedMethodContainingTypeMissingModifiers =
290292
new DiagnosticDescriptor(
291-
Ids.InvalidJSImportAttributeUsage,
292-
GetResourceString(nameof(SR.InvalidJSImportAttributeUsageTitle)),
293+
Ids.InvalidJSExportAttributeUsage,
294+
GetResourceString(nameof(SR.InvalidJSExportAttributeUsageTitle)),
293295
GetResourceString(nameof(SR.InvalidAttributedMethodContainingTypeMissingModifiersMessage)),
294296
Category,
295297
DiagnosticSeverity.Error,
296298
isEnabledByDefault: true,
297299
description: GetResourceString(nameof(SR.InvalidJSExportAttributedMethodDescription)));
298300

301+
public static readonly DiagnosticDescriptor JSImportRequiresAllowUnsafeBlocks =
302+
new DiagnosticDescriptor(
303+
Ids.JSImportRequiresAllowUnsafeBlocks,
304+
GetResourceString(nameof(SR.JSImportRequiresAllowUnsafeBlocksTitle)),
305+
GetResourceString(nameof(SR.JSImportRequiresAllowUnsafeBlocksMessage)),
306+
Category,
307+
DiagnosticSeverity.Error,
308+
isEnabledByDefault: true,
309+
description: GetResourceString(nameof(SR.JSImportRequiresAllowUnsafeBlocksDescription)));
310+
311+
public static readonly DiagnosticDescriptor JSExportRequiresAllowUnsafeBlocks =
312+
new DiagnosticDescriptor(
313+
Ids.JSExportRequiresAllowUnsafeBlocks,
314+
GetResourceString(nameof(SR.JSExportRequiresAllowUnsafeBlocksTitle)),
315+
GetResourceString(nameof(SR.JSExportRequiresAllowUnsafeBlocksMessage)),
316+
Category,
317+
DiagnosticSeverity.Error,
318+
isEnabledByDefault: true,
319+
description: GetResourceString(nameof(SR.JSExportRequiresAllowUnsafeBlocksDescription)));
320+
299321
private static LocalizableResourceString GetResourceString(string resourceName)
300322
{
301323
return new LocalizableResourceString(resourceName, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.JavaScript.JSImportGenerator.SR));

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public static class StepNames
5353

5454
public void Initialize(IncrementalGeneratorInitializationContext context)
5555
{
56+
// Collect all methods adorned with JSExportAttribute
5657
var attributedMethods = context.SyntaxProvider
5758
.CreateSyntaxProvider(
5859
static (node, ct) => ShouldVisitNode(node),
@@ -70,6 +71,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7071
.Where(
7172
static modelData => modelData is not null);
7273

74+
// Validate if attributed methods can have source generated
7375
var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) =>
7476
{
7577
Diagnostic? diagnostic = GetDiagnosticIfInvalidMethodForGeneration(data.Syntax, data.Symbol);
@@ -79,16 +81,32 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7981
var methodsToGenerate = methodsWithDiagnostics.Where(static data => data.Diagnostic is null);
8082
var invalidMethodDiagnostics = methodsWithDiagnostics.Where(static data => data.Diagnostic is not null);
8183

84+
// Report diagnostics for invalid methods
8285
context.RegisterSourceOutput(invalidMethodDiagnostics, static (context, invalidMethod) =>
8386
{
8487
context.ReportDiagnostic(invalidMethod.Diagnostic);
8588
});
8689

90+
// Compute generator options
8791
IncrementalValueProvider<JSGeneratorOptions> stubOptions = context.AnalyzerConfigOptionsProvider
8892
.Select(static (options, ct) => new JSGeneratorOptions(options.GlobalOptions));
8993

94+
IncrementalValueProvider<StubEnvironment> stubEnvironment = context.CreateStubEnvironmentProvider();
95+
96+
// Validate environment that is being used to generate stubs.
97+
context.RegisterDiagnostics(stubEnvironment.Combine(attributedMethods.Collect()).SelectMany((data, ct) =>
98+
{
99+
if (data.Right.IsEmpty // no attributed methods
100+
|| data.Left.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }) // Unsafe code enabled
101+
{
102+
return ImmutableArray<Diagnostic>.Empty;
103+
}
104+
105+
return ImmutableArray.Create(Diagnostic.Create(GeneratorDiagnostics.JSExportRequiresAllowUnsafeBlocks, null));
106+
}));
107+
90108
IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateSingleStub = methodsToGenerate
91-
.Combine(context.CreateStubEnvironmentProvider())
109+
.Combine(stubEnvironment)
92110
.Combine(stubOptions)
93111
.Select(static (data, ct) => new
94112
{

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportGenerator.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public static class StepNames
5858

5959
public void Initialize(IncrementalGeneratorInitializationContext context)
6060
{
61+
// Collect all methods adorned with JSImportAttribute
6162
var attributedMethods = context.SyntaxProvider
6263
.CreateSyntaxProvider(
6364
static (node, ct) => ShouldVisitNode(node),
@@ -75,6 +76,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7576
.Where(
7677
static modelData => modelData is not null);
7778

79+
// Validate if attributed methods can have source generated
7880
var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) =>
7981
{
8082
Diagnostic? diagnostic = GetDiagnosticIfInvalidMethodForGeneration(data.Syntax, data.Symbol);
@@ -84,16 +86,32 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8486
var methodsToGenerate = methodsWithDiagnostics.Where(static data => data.Diagnostic is null);
8587
var invalidMethodDiagnostics = methodsWithDiagnostics.Where(static data => data.Diagnostic is not null);
8688

89+
// Report diagnostics for invalid methods
8790
context.RegisterSourceOutput(invalidMethodDiagnostics, static (context, invalidMethod) =>
8891
{
8992
context.ReportDiagnostic(invalidMethod.Diagnostic);
9093
});
9194

95+
// Compute generator options
9296
IncrementalValueProvider<JSGeneratorOptions> stubOptions = context.AnalyzerConfigOptionsProvider
9397
.Select(static (options, ct) => new JSGeneratorOptions(options.GlobalOptions));
9498

99+
IncrementalValueProvider<StubEnvironment> stubEnvironment = context.CreateStubEnvironmentProvider();
100+
101+
// Validate environment that is being used to generate stubs.
102+
context.RegisterDiagnostics(stubEnvironment.Combine(attributedMethods.Collect()).SelectMany((data, ct) =>
103+
{
104+
if (data.Right.IsEmpty // no attributed methods
105+
|| data.Left.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }) // Unsafe code enabled
106+
{
107+
return ImmutableArray<Diagnostic>.Empty;
108+
}
109+
110+
return ImmutableArray.Create(Diagnostic.Create(GeneratorDiagnostics.JSImportRequiresAllowUnsafeBlocks, null));
111+
}));
112+
95113
IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateSingleStub = methodsToGenerate
96-
.Combine(context.CreateStubEnvironmentProvider())
114+
.Combine(stubEnvironment)
97115
.Combine(stubOptions)
98116
.Select(static (data, ct) => new
99117
{

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,22 @@
208208
<value>Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of {0}.</value>
209209
<comment>{0} is a type of the argument</comment>
210210
</data>
211+
<data name="JSImportRequiresAllowUnsafeBlocksDescription" xml:space="preserve">
212+
<value>JSImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</value>
213+
</data>
214+
<data name="JSImportRequiresAllowUnsafeBlocksMessage" xml:space="preserve">
215+
<value>JSImportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</value>
216+
</data>
217+
<data name="JSImportRequiresAllowUnsafeBlocksTitle" xml:space="preserve">
218+
<value>JSImportAttribute requires unsafe code.</value>
219+
</data>
220+
<data name="JSExportRequiresAllowUnsafeBlocksDescription" xml:space="preserve">
221+
<value>JSExportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</value>
222+
</data>
223+
<data name="JSExportRequiresAllowUnsafeBlocksMessage" xml:space="preserve">
224+
<value>JSExportAttribute requires unsafe code. Project must be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</value>
225+
</data>
226+
<data name="JSExportRequiresAllowUnsafeBlocksTitle" xml:space="preserve">
227+
<value>JSExportAttribute requires unsafe code.</value>
228+
</data>
211229
</root>

src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Compiles.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public static IEnumerable<object[]> CodeSnippetsToCompile()
3232
[MemberData(nameof(CodeSnippetsToCompile))]
3333
public async Task ValidateSnippets(string source)
3434
{
35-
Compilation comp = await TestUtils.CreateCompilation(source);
35+
Compilation comp = await TestUtils.CreateCompilation(source, allowUnsafe: true);
3636
TestUtils.AssertPreSourceGeneratorCompilation(comp);
3737

3838
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags,

src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public class Fails
5555
[MemberData(nameof(CodeSnippetsToFail))]
5656
public async Task ValidateFailSnippets(string source, string[]? generatorMessages, string[]? compilerMessages)
5757
{
58-
Compilation comp = await TestUtils.CreateCompilation(source);
58+
Compilation comp = await TestUtils.CreateCompilation(source, allowUnsafe: true);
5959
TestUtils.AssertPreSourceGeneratorCompilation(comp);
6060

6161
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags,
@@ -73,5 +73,21 @@ public async Task ValidateFailSnippets(string source, string[]? generatorMessage
7373
JSTestUtils.AssertMessages(compilationDiags, compilerMessages);
7474
}
7575
}
76+
77+
[Fact]
78+
public async Task ValidateRequireAllowUnsafeBlocksDiagnostic()
79+
{
80+
string source = CodeSnippets.TrivialClassDeclarations;
81+
Compilation comp = await TestUtils.CreateCompilation(new[] { source }, allowUnsafe: false);
82+
TestUtils.AssertPreSourceGeneratorCompilation(comp);
83+
84+
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags,
85+
new Microsoft.Interop.JavaScript.JSImportGenerator(),
86+
new Microsoft.Interop.JavaScript.JSExportGenerator());
87+
88+
// The errors should indicate the AllowUnsafeBlocks is required.
89+
Assert.True(generatorDiags.Single(d => d.Id == "SYSLIB1074") != null);
90+
Assert.True(generatorDiags.Single(d => d.Id == "SYSLIB1075") != null);
91+
}
7692
}
7793
}

src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Tests.csproj renamed to src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj

File renamed without changes.

0 commit comments

Comments
 (0)