Skip to content

Commit 59fa991

Browse files
authored
Allow specifying emit options (#83)
2 parents 6af09fc + aaa1621 commit 59fa991

File tree

10 files changed

+91
-25
lines changed

10 files changed

+91
-25
lines changed

Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<NoWarn>$(NoWarn);NU1507</NoWarn>
77
<NetCoreVersion>10.0.0-preview.5.25277.114</NetCoreVersion>
88
<AspNetCoreVersion>$(NetCoreVersion)</AspNetCoreVersion>
9-
<RoslynVersion>5.0.0-1.25321.102</RoslynVersion>
9+
<RoslynVersion>5.0.0-1.25357.1</RoslynVersion>
1010
<FluentUIVersion>4.12.0</FluentUIVersion>
1111
<NuGetVersion>6.14.0</NuGetVersion>
1212
</PropertyGroup>
@@ -31,7 +31,7 @@
3131
<PackageVersion Include="Microsoft.Extensions.Logging" Version="$(NetCoreVersion)" />
3232
<PackageVersion Include="Microsoft.FluentUI.AspNetCore.Components" Version="$(FluentUIVersion)" />
3333
<PackageVersion Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="$(FluentUIVersion)" />
34-
<PackageVersion Include="Microsoft.Net.Compilers.Razor.Toolset" Version="10.0.0-preview.25321.102" />
34+
<PackageVersion Include="Microsoft.Net.Compilers.Razor.Toolset" Version="10.0.0-preview.25353.4" />
3535
<PackageVersion Include="Microsoft.Net.Compilers.Toolset" Version="$(RoslynVersion)" />
3636
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
3737
<PackageVersion Include="Microsoft.NETCore.App.Ref" Version="$(NetCoreVersion)" />

src/App/Lab/InitialCode.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static void Main()
3333
[Parameter] public int Param { get; set; }
3434
}
3535
36-
""");
36+
""".ReplaceLineEndings());
3737

3838
// https://github.com/dotnet/aspnetcore/blob/036ec9ec2ffbfe927f9eb7622dfff122c634ccbb/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/_Imports.razor
3939
public static readonly InitialCode RazorImports = new("_Imports.razor", """
@@ -47,7 +47,7 @@ @using static Microsoft.AspNetCore.Components.Web.RenderMode
4747
@using Microsoft.AspNetCore.Components.Web.Virtualization
4848
@using Microsoft.JSInterop
4949
50-
""");
50+
""".ReplaceLineEndings());
5151

5252
public static readonly InitialCode Cshtml = new("TestPage.cshtml", """
5353
@page
@@ -76,7 +76,7 @@ public class Customer
7676
}
7777
}
7878
79-
""");
79+
""".ReplaceLineEndings());
8080

8181
// IMPORTANT: Keep in sync with `Compiler.Compile`.
8282
public static readonly InitialCode Configuration = new("Configuration.cs", """
@@ -91,6 +91,10 @@ public class Customer
9191
.WithOptimizationLevel(OptimizationLevel.Debug)
9292
);
9393
94+
Config.EmitOptions(options => options
95+
.WithEmitMetadataOnly(false)
96+
);
97+
9498
""");
9599

96100
public InitialCode(string suggestedFileName, string textTemplate)

src/App/Lab/TemplateCache.cs

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

src/Compiler/Api.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
using Microsoft.CodeAnalysis.CSharp;
2+
using Microsoft.CodeAnalysis.Emit;
23

34
namespace DotNetLab;
45

56
public static class Config
67
{
78
private static readonly List<Func<CSharpParseOptions, CSharpParseOptions>> cSharpParseOptions = new();
89
private static readonly List<Func<CSharpCompilationOptions, CSharpCompilationOptions>> cSharpCompilationOptions = new();
10+
private static readonly List<Func<EmitOptions, EmitOptions>> emitOptions = new();
911

1012
internal static void Reset()
1113
{
1214
cSharpParseOptions.Clear();
1315
cSharpCompilationOptions.Clear();
16+
emitOptions.Clear();
1417
}
1518

1619
public static void CSharpParseOptions(Func<CSharpParseOptions, CSharpParseOptions> configure)
@@ -23,10 +26,17 @@ public static void CSharpCompilationOptions(Func<CSharpCompilationOptions, CShar
2326
cSharpCompilationOptions.Add(configure);
2427
}
2528

29+
public static void EmitOptions(Func<EmitOptions, EmitOptions> configure)
30+
{
31+
emitOptions.Add(configure);
32+
}
33+
2634
internal static CSharpParseOptions ConfigureCSharpParseOptions(CSharpParseOptions options) => Configure(options, cSharpParseOptions);
2735

2836
internal static CSharpCompilationOptions ConfigureCSharpCompilationOptions(CSharpCompilationOptions options) => Configure(options, cSharpCompilationOptions);
2937

38+
internal static EmitOptions ConfigureEmitOptions(EmitOptions options) => Configure(options, emitOptions);
39+
3040
private static T Configure<T>(T options, List<Func<T, T>> configureList)
3141
{
3242
foreach (var configure in configureList)

src/Compiler/Compiler.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.CodeAnalysis.CSharp;
66
using Microsoft.CodeAnalysis.CSharp.Syntax;
77
using Microsoft.CodeAnalysis.Diagnostics;
8+
using Microsoft.CodeAnalysis.Emit;
89
using Microsoft.CodeAnalysis.Razor;
910
using Microsoft.CodeAnalysis.Text;
1011
using Microsoft.Extensions.Logging;
@@ -27,6 +28,7 @@ You can try selecting different Razor toolchain in Settings / Advanced.
2728
global using DotNetLab;
2829
global using Microsoft.CodeAnalysis;
2930
global using Microsoft.CodeAnalysis.CSharp;
31+
global using Microsoft.CodeAnalysis.Emit;
3032
global using System;
3133
""";
3234

@@ -67,6 +69,7 @@ private LiveCompilationResult CompileNoCache(
6769

6870
var parseOptions = CreateDefaultParseOptions();
6971
CSharpCompilationOptions? options = null;
72+
EmitOptions emitOptions = EmitOptions.Default;
7073

7174
var references = RefAssemblyMetadata.All;
7275
var referenceInfos = RefAssemblies.All;
@@ -106,6 +109,7 @@ private LiveCompilationResult CompileNoCache(
106109
}
107110

108111
parseOptions = Config.ConfigureCSharpParseOptions(parseOptions);
112+
emitOptions = Config.ConfigureEmitOptions(emitOptions);
109113
}
110114
else
111115
{
@@ -640,7 +644,7 @@ CSharpCompilation getExecutableCompilation()
640644
MemoryStream? getEmitStream(CSharpCompilation compilation, out ImmutableArray<Diagnostic> diagnostics)
641645
{
642646
var stream = new MemoryStream();
643-
var emitResult = compilation.Emit(stream);
647+
var emitResult = compilation.Emit(stream, options: emitOptions);
644648
if (!emitResult.Success)
645649
{
646650
diagnostics = emitResult.Diagnostics;

src/Compiler/RefAssemblyMetadata.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ private static ImmutableArray<PortableExecutableReference> GetAll()
1414
foreach (var assembly in all)
1515
{
1616
builder.Add(AssemblyMetadata.CreateFromImage(assembly.Bytes)
17-
.GetReference(filePath: assembly.FileName, display: assembly.Name));
17+
.GetReference(filePath: assembly.FileName, display: assembly.FileName));
1818
}
1919

2020
return builder.DrainToImmutable();

src/Compiler/Utils/Utils.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.AspNetCore.Razor.Language.Intermediate;
33
using Microsoft.CodeAnalysis;
44
using Microsoft.CodeAnalysis.CSharp;
5+
using Microsoft.CodeAnalysis.Emit;
56
using Microsoft.CodeAnalysis.Text;
67
using System.Numerics;
78
using System.Reflection.Emit;
@@ -11,6 +12,13 @@ namespace DotNetLab;
1112

1213
public static class CodeAnalysisUtil
1314
{
15+
private static EmitOptions DefaultEmitOptions => field ??= new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb);
16+
17+
extension(EmitOptions)
18+
{
19+
public static EmitOptions Default => DefaultEmitOptions;
20+
}
21+
1422
public static bool TryGetHostOutputSafe(
1523
this GeneratorRunResult result,
1624
string key,

src/Worker/Lab/NuGetDownloader.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,18 +139,13 @@ public NuGetDownloader(
139139
var stream = new MemoryStream();
140140
var success = await finders.SelectAsync(async (f) =>
141141
{
142-
bool success;
143-
try
144-
{
145-
success = await f.Resource.CopyNupkgToStreamAsync(
146-
info.PackageId,
147-
version,
148-
stream,
149-
cacheContext,
150-
NullLogger.Instance,
151-
CancellationToken.None);
152-
}
153-
catch (Newtonsoft.Json.JsonReaderException) { success = false; }
142+
bool success = await f.Resource.CopyNupkgToStreamAsync(
143+
info.PackageId,
144+
version,
145+
stream,
146+
cacheContext,
147+
NullLogger.Instance,
148+
CancellationToken.None);
154149
return (Success: success, f.NuGetOrg);
155150
})
156151
.FirstOrNullAsync(static t => t.Success);
@@ -245,8 +240,16 @@ public CustomHttpHandlerResourceV3Provider(NuGetDownloader nuGetDownloader)
245240
}
246241
}
247242

248-
internal sealed class CorsClientHandler(NuGetDownloader nuGetDownloader) : HttpClientHandler
243+
internal sealed class CorsClientHandler : HttpClientHandler
249244
{
245+
private readonly NuGetDownloader nuGetDownloader;
246+
247+
public CorsClientHandler(NuGetDownloader nuGetDownloader)
248+
{
249+
this.nuGetDownloader = nuGetDownloader;
250+
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
251+
}
252+
250253
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
251254
{
252255
if (request.RequestUri?.AbsolutePath.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase) == true)

test/UnitTests/CompilerProxyTests.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ namespace DotNetLab;
77
public sealed class CompilerProxyTests(ITestOutputHelper output)
88
{
99
[Theory]
10-
[InlineData("4.12.0-2.24409.2", "4.12.0-2.24409.2 (2158b591)")]
11-
[InlineData("main", "-ci (<developer build>)")]
10+
[InlineData("4.12.0-2.24409.2", "4.12.0-2.24409.2 (2158b591)")] // preview version is downloaded from an AzDo feed
11+
[InlineData("4.14.0", "4.14.0-3.25262.10 (8edf7bcd)")] // non-preview version is downloaded from nuget.org
12+
[InlineData("main", "-ci (<developer build>)")] // a branch can be downloaded
1213
public async Task SpecifiedNuGetRoslynVersion(string version, string expectedDiagnostic)
1314
{
1415
var services = WorkerServices.CreateTest(new MockHttpMessageHandler(output));
@@ -25,12 +26,31 @@ await services.GetRequiredService<CompilerDependencyProvider>()
2526
Assert.Contains(expectedDiagnostic, diagnosticsText);
2627

2728
// Language services should also pick up the custom compiler version.
29+
// There are bunch of tests that do not assert much but they verify no type load exceptions happen.
30+
// Some older versions of Roslyn are not compatible though (until we actually download the corresponding older DLLs
31+
// for language services as well but we might never actually want to support that).
32+
2833
var languageServices = await compiler.GetLanguageServicesAsync();
2934
await languageServices.OnDidChangeWorkspaceAsync([new("Input.cs", "Input.cs") { NewContent = "#error version" }]);
3035

3136
var markers = await languageServices.GetDiagnosticsAsync("Input.cs");
3237
markers.Should().Contain(m => m.Message.Contains(expectedDiagnostic));
3338

39+
var loadSemanticTokens = async () =>
40+
{
41+
var semanticTokensJson = await languageServices.ProvideSemanticTokensAsync("Input.cs", null, false, TestContext.Current.CancellationToken);
42+
semanticTokensJson.Should().NotBeNull();
43+
};
44+
45+
if (version.StartsWith("4.12."))
46+
{
47+
await loadSemanticTokens.Should().ThrowAsync<TypeLoadException>();
48+
}
49+
else
50+
{
51+
await loadSemanticTokens();
52+
}
53+
3454
var codeActionsJson = await languageServices.ProvideCodeActionsAsync("Input.cs", null, TestContext.Current.CancellationToken);
3555
codeActionsJson.Should().NotBeNull();
3656
}
@@ -65,7 +85,7 @@ await services.GetRequiredService<CompilerDependencyProvider>()
6585
// /Input.cs(1,8): error CS8304: Compiler version: '{version} ({commit})'. Language version: 10.0.
6686
// #error version
6787
Diagnostic(ErrorCode.ERR_CompilerAndLanguageVersion, "version").WithArguments("{version} ({commit})", "10.0").WithLocation(1, 8)
68-
""", diagnosticsText);
88+
""".ReplaceLineEndings(), diagnosticsText);
6989
}
7090

7191
[Theory]
@@ -129,6 +149,10 @@ public async Task SpecifiedRazorOptions(RazorToolchain toolchain, RazorStrategy
129149

130150
string code = """
131151
<div>@Param</div>
152+
@if (Param == 0)
153+
{
154+
<TestComponent Param="1" />
155+
}
132156
133157
@code {
134158
[Parameter] public int Param { get; set; } = 42;
@@ -150,6 +174,7 @@ public async Task SpecifiedRazorOptions(RazorToolchain toolchain, RazorStrategy
150174
var cSharpText = await compiled.GetRequiredGlobalOutput("cs").GetTextAsync(outputFactory: null);
151175
output.WriteLine(cSharpText);
152176
Assert.Contains("class TestComponent", cSharpText);
177+
Assert.Contains("AddComponentParameter", cSharpText);
153178

154179
var htmlText = await compiled.Files.Single().Value.GetRequiredOutput("html").GetTextAsync(outputFactory: null);
155180
output.WriteLine(htmlText);

testEnvironments.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "1",
3+
"environments": [
4+
// See https://aka.ms/remotetesting for more details
5+
// about how to configure remote environments.
6+
{
7+
"name": "WSL Ubuntu",
8+
"type": "wsl",
9+
"wslDistribution": "Ubuntu"
10+
}
11+
]
12+
}

0 commit comments

Comments
 (0)