Skip to content

Commit e9a22b0

Browse files
jjonesczchsienki
andcommitted
Add ExternalAccess.RazorCompiler project with host outputs API (#65831)
* Initial experimental API project - Add host outputs to exerimental API surface - Enable internal hosts outputs in generator driver * Move project, add nuget package, add to sln * PR Feedback * Update unreachable calls * Update nullability * Suppress unused parameter warning * Add project to `Compilers.slnf` * Move to new ExternalAccess project * Remove an old IVT * Add project to compiler solutions * Assign project to Roslyn compiler team Co-authored-by: Chris Sienkiewicz <[email protected]>
1 parent 4b579bb commit e9a22b0

16 files changed

+248
-8
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ src/Features/**/PublicAPI.Unshipped.txt @dotnet/roslyn-api-owners
5151
src/EditorFeatures/**/PublicAPI.Unshipped.txt @dotnet/roslyn-api-owners
5252

5353
src/Tools/ExternalAccess/OmniSharp*/ @333fred @joerobich
54+
src/Tools/ExternalAccess/RazorCompiler @dotnet/roslyn-compiler

Compilers.sln

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.CSha
165165
EndProject
166166
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDiscoveryWorker", "src\Tools\TestDiscoveryWorker\TestDiscoveryWorker.csproj", "{FB617466-C4A1-4289-A512-A06182FC779F}"
167167
EndProject
168+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExternalAccess", "ExternalAccess", "{67B6F694-CA27-4CDE-B1E5-E2B4105A2420}"
169+
EndProject
170+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler", "src\Tools\ExternalAccess\RazorCompiler\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj", "{8450EF6B-28BB-4F4D-B005-CD734B476800}"
171+
EndProject
168172
Global
169173
GlobalSection(SolutionConfigurationPlatforms) = preSolution
170174
Debug|Any CPU = Debug|Any CPU
@@ -423,6 +427,10 @@ Global
423427
{FB617466-C4A1-4289-A512-A06182FC779F}.Debug|Any CPU.Build.0 = Debug|Any CPU
424428
{FB617466-C4A1-4289-A512-A06182FC779F}.Release|Any CPU.ActiveCfg = Release|Any CPU
425429
{FB617466-C4A1-4289-A512-A06182FC779F}.Release|Any CPU.Build.0 = Release|Any CPU
430+
{8450EF6B-28BB-4F4D-B005-CD734B476800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
431+
{8450EF6B-28BB-4F4D-B005-CD734B476800}.Debug|Any CPU.Build.0 = Debug|Any CPU
432+
{8450EF6B-28BB-4F4D-B005-CD734B476800}.Release|Any CPU.ActiveCfg = Release|Any CPU
433+
{8450EF6B-28BB-4F4D-B005-CD734B476800}.Release|Any CPU.Build.0 = Release|Any CPU
426434
EndGlobalSection
427435
GlobalSection(SolutionProperties) = preSolution
428436
HideSolutionNode = FALSE
@@ -499,6 +507,8 @@ Global
499507
{48C93F90-8776-4847-96D8-127B896D6C80} = {C65C6143-BED3-46E6-869E-9F0BE6E84C37}
500508
{F3D9264A-7CAE-4265-AF48-0C863301F51E} = {32A48625-F0AD-419D-828B-A50BDABA38EA}
501509
{FB617466-C4A1-4289-A512-A06182FC779F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
510+
{67B6F694-CA27-4CDE-B1E5-E2B4105A2420} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
511+
{8450EF6B-28BB-4F4D-B005-CD734B476800} = {67B6F694-CA27-4CDE-B1E5-E2B4105A2420}
502512
EndGlobalSection
503513
GlobalSection(ExtensibilityGlobals) = postSolution
504514
SolutionGuid = {6F599E08-A9EA-4FAA-897F-5D824B0210E6}

Compilers.slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"src\\Test\\PdbUtilities\\Roslyn.Test.PdbUtilities.csproj",
4545
"src\\Compilers\\Test\\Core\\Microsoft.CodeAnalysis.Test.Utilities.csproj",
4646
"src\\Tools\\AnalyzerRunner\\AnalyzerRunner.csproj",
47+
"src\\Tools\\ExternalAccess\\RazorCompiler\\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj",
4748
"src\\Tools\\Source\\CompilerGeneratorTools\\Source\\BoundTreeGenerator\\CompilersBoundTreeGenerator.csproj",
4849
"src\\Tools\\Source\\CompilerGeneratorTools\\Source\\CSharpErrorFactsGenerator\\CSharpErrorFactsGenerator.csproj",
4950
"src\\Tools\\Source\\CompilerGeneratorTools\\Source\\CSharpSyntaxGenerator\\CSharpSyntaxGenerator.csproj",

Roslyn.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ Project("{778dae3c-4631-46ea-aa77-85c1314464d9}") = "Microsoft.CodeAnalysis.Visu
523523
EndProject
524524
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDiscoveryWorker", "src\Tools\TestDiscoveryWorker\TestDiscoveryWorker.csproj", "{8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}"
525525
EndProject
526+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler", "src\Tools\ExternalAccess\RazorCompiler\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj", "{E5E0BF73-95F7-4BC3-8443-2336C4FF4297}"
527+
EndProject
526528
Global
527529
GlobalSection(SolutionConfigurationPlatforms) = preSolution
528530
Debug|Any CPU = Debug|Any CPU
@@ -1277,6 +1279,10 @@ Global
12771279
{8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}.Debug|Any CPU.Build.0 = Debug|Any CPU
12781280
{8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}.Release|Any CPU.ActiveCfg = Release|Any CPU
12791281
{8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F}.Release|Any CPU.Build.0 = Release|Any CPU
1282+
{E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1283+
{E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Debug|Any CPU.Build.0 = Debug|Any CPU
1284+
{E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Release|Any CPU.ActiveCfg = Release|Any CPU
1285+
{E5E0BF73-95F7-4BC3-8443-2336C4FF4297}.Release|Any CPU.Build.0 = Release|Any CPU
12801286
EndGlobalSection
12811287
GlobalSection(SolutionProperties) = preSolution
12821288
HideSolutionNode = FALSE
@@ -1515,6 +1521,7 @@ Global
15151521
{4C1B26EE-465B-4B30-9E50-0285EF7AB035} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6}
15161522
{F836BDB1-4EC7-4F4C-B2E9-BCD721C9E650} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6}
15171523
{8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
1524+
{E5E0BF73-95F7-4BC3-8443-2336C4FF4297} = {8977A560-45C2-4EC2-A849-97335B382C74}
15181525
EndGlobalSection
15191526
GlobalSection(ExtensibilityGlobals) = postSolution
15201527
SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29}

src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ExpressionCompiler.UnitTests" />
8181
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.ExpressionCompiler.UnitTests" />
8282
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExpressionEvaluator.ExpressionCompiler.Utilities" />
83+
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler" />
8384
<InternalsVisibleTo Include="InteractiveHost.UnitTests" />
8485
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Scripting.UnitTests" />
8586
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Scripting.Desktop.UnitTests" />

src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ public GeneratorDriverRunResult GetRunResult()
163163
generatedSources: getGeneratorSources(generatorState),
164164
elapsedTime: generatorState.ElapsedTime,
165165
namedSteps: generatorState.ExecutedSteps,
166-
outputSteps: generatorState.OutputSteps));
166+
outputSteps: generatorState.OutputSteps,
167+
hostOutputs: generatorState.HostOutputs));
167168
return new GeneratorDriverRunResult(results, _state.RunTime);
168169

169170
static ImmutableArray<GeneratedSourceResult> getGeneratorSources(GeneratorState generatorState)
@@ -293,10 +294,10 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos
293294
{
294295
// We do not support incremental step tracking for v1 generators, as the pipeline is implicitly defined.
295296
var context = UpdateOutputs(generatorState.OutputNodes, IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.Implementation, new GeneratorRunStateTable.Builder(state.TrackIncrementalSteps), cancellationToken, driverStateBuilder);
296-
(var sources, var generatorDiagnostics, var generatorRunStateTable) = context.ToImmutableAndFree();
297+
(var sources, var generatorDiagnostics, var generatorRunStateTable, var hostOutputs) = context.ToImmutableAndFree();
297298
generatorDiagnostics = FilterDiagnostics(compilation, generatorDiagnostics, driverDiagnostics: diagnosticsBag, cancellationToken);
298299

299-
stateBuilder[i] = generatorState.WithResults(ParseAdditionalSources(state.Generators[i], sources, cancellationToken), generatorDiagnostics, generatorRunStateTable.ExecutedSteps, generatorRunStateTable.OutputSteps, generatorTimer.Elapsed);
300+
stateBuilder[i] = generatorState.WithResults(ParseAdditionalSources(state.Generators[i], sources, cancellationToken), generatorDiagnostics, generatorRunStateTable.ExecutedSteps, generatorRunStateTable.OutputSteps, hostOutputs, generatorTimer.Elapsed);
300301
}
301302
catch (UserFunctionException ufe)
302303
{

src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Immutable;
77
using System.Diagnostics;
8+
89
namespace Microsoft.CodeAnalysis
910
{
1011
/// <summary>
@@ -20,18 +21,38 @@ internal readonly struct GeneratorState
2021
ImmutableArray<Diagnostic>.Empty,
2122
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty,
2223
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty,
24+
ImmutableArray<(string, string)>.Empty,
2325
exception: null,
2426
elapsedTime: TimeSpan.Zero);
2527

2628
/// <summary>
2729
/// Creates a new generator state that contains information, constant trees and an execution pipeline
2830
/// </summary>
2931
public GeneratorState(ImmutableArray<GeneratedSyntaxTree> postInitTrees, ImmutableArray<SyntaxInputNode> inputNodes, ImmutableArray<IIncrementalGeneratorOutputNode> outputNodes)
30-
: this(postInitTrees, inputNodes, outputNodes, ImmutableArray<GeneratedSyntaxTree>.Empty, ImmutableArray<Diagnostic>.Empty, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty, exception: null, elapsedTime: TimeSpan.Zero)
32+
: this(postInitTrees,
33+
inputNodes,
34+
outputNodes,
35+
ImmutableArray<GeneratedSyntaxTree>.Empty,
36+
ImmutableArray<Diagnostic>.Empty,
37+
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty,
38+
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty,
39+
ImmutableArray<(string, string)>.Empty,
40+
exception: null,
41+
elapsedTime: TimeSpan.Zero)
3142
{
3243
}
3344

34-
private GeneratorState(ImmutableArray<GeneratedSyntaxTree> postInitTrees, ImmutableArray<SyntaxInputNode> inputNodes, ImmutableArray<IIncrementalGeneratorOutputNode> outputNodes, ImmutableArray<GeneratedSyntaxTree> generatedTrees, ImmutableArray<Diagnostic> diagnostics, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> executedSteps, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> outputSteps, Exception? exception, TimeSpan elapsedTime)
45+
private GeneratorState(
46+
ImmutableArray<GeneratedSyntaxTree> postInitTrees,
47+
ImmutableArray<SyntaxInputNode> inputNodes,
48+
ImmutableArray<IIncrementalGeneratorOutputNode> outputNodes,
49+
ImmutableArray<GeneratedSyntaxTree> generatedTrees,
50+
ImmutableArray<Diagnostic> diagnostics,
51+
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> executedSteps,
52+
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> outputSteps,
53+
ImmutableArray<(string Key, string Value)> hostOutputs,
54+
Exception? exception,
55+
TimeSpan elapsedTime)
3556
{
3657
this.Initialized = true;
3758
this.PostInitTrees = postInitTrees;
@@ -41,6 +62,7 @@ private GeneratorState(ImmutableArray<GeneratedSyntaxTree> postInitTrees, Immuta
4162
this.Diagnostics = diagnostics;
4263
this.ExecutedSteps = executedSteps;
4364
this.OutputSteps = outputSteps;
65+
this.HostOutputs = hostOutputs;
4466
this.Exception = exception;
4567
this.ElapsedTime = elapsedTime;
4668
}
@@ -49,6 +71,7 @@ public GeneratorState WithResults(ImmutableArray<GeneratedSyntaxTree> generatedT
4971
ImmutableArray<Diagnostic> diagnostics,
5072
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> executedSteps,
5173
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> outputSteps,
74+
ImmutableArray<(string Key, string Value)> hostOutputs,
5275
TimeSpan elapsedTime)
5376
{
5477
return new GeneratorState(this.PostInitTrees,
@@ -58,6 +81,7 @@ public GeneratorState WithResults(ImmutableArray<GeneratedSyntaxTree> generatedT
5881
diagnostics,
5982
executedSteps,
6083
outputSteps,
84+
hostOutputs,
6185
exception: null,
6286
elapsedTime);
6387
}
@@ -71,6 +95,7 @@ public GeneratorState WithError(Exception exception, Diagnostic error, TimeSpan
7195
ImmutableArray.Create(error),
7296
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty,
7397
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty,
98+
ImmutableArray<(string, string)>.Empty,
7499
exception,
75100
elapsedTime);
76101
}
@@ -94,5 +119,7 @@ public GeneratorState WithError(Exception exception, Diagnostic error, TimeSpan
94119
internal ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> ExecutedSteps { get; }
95120

96121
internal ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> OutputSteps { get; }
122+
123+
internal ImmutableArray<(string Key, string Value)> HostOutputs { get; }
97124
}
98125
}

src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Collections.Generic;
67
using System.Collections.Immutable;
78
using System.Text;
89
using System.Threading;
@@ -166,16 +167,19 @@ internal readonly struct IncrementalExecutionContext
166167

167168
internal readonly GeneratorRunStateTable.Builder GeneratorRunStateBuilder;
168169

170+
internal readonly ArrayBuilder<(string Key, string Value)> HostOutputBuilder;
171+
169172
public IncrementalExecutionContext(DriverStateTable.Builder? tableBuilder, GeneratorRunStateTable.Builder generatorRunStateBuilder, AdditionalSourcesCollection sources)
170173
{
171174
TableBuilder = tableBuilder;
172175
GeneratorRunStateBuilder = generatorRunStateBuilder;
173176
Sources = sources;
177+
HostOutputBuilder = ArrayBuilder<(string, string)>.GetInstance();
174178
Diagnostics = DiagnosticBag.GetInstance();
175179
}
176180

177-
internal (ImmutableArray<GeneratedSourceText> sources, ImmutableArray<Diagnostic> diagnostics, GeneratorRunStateTable executedSteps) ToImmutableAndFree()
178-
=> (Sources.ToImmutableAndFree(), Diagnostics.ToReadOnlyAndFree(), GeneratorRunStateBuilder.ToImmutableAndFree());
181+
internal (ImmutableArray<GeneratedSourceText> sources, ImmutableArray<Diagnostic> diagnostics, GeneratorRunStateTable executedSteps, ImmutableArray<(string Key, string Value)> hostOutputs) ToImmutableAndFree()
182+
=> (Sources.ToImmutableAndFree(), Diagnostics.ToReadOnlyAndFree(), GeneratorRunStateBuilder.ToImmutableAndFree(), HostOutputBuilder.ToImmutableAndFree());
179183

180184
internal void Free()
181185
{

src/Compilers/Core/Portable/SourceGeneration/RunResults.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,15 @@ public ImmutableArray<SyntaxTree> GeneratedTrees
7777
/// </summary>
7878
public readonly struct GeneratorRunResult
7979
{
80-
internal GeneratorRunResult(ISourceGenerator generator, ImmutableArray<GeneratedSourceResult> generatedSources, ImmutableArray<Diagnostic> diagnostics, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> namedSteps, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> outputSteps, Exception? exception, TimeSpan elapsedTime)
80+
internal GeneratorRunResult(
81+
ISourceGenerator generator,
82+
ImmutableArray<GeneratedSourceResult> generatedSources,
83+
ImmutableArray<Diagnostic> diagnostics,
84+
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> namedSteps,
85+
ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> outputSteps,
86+
ImmutableArray<(string Key, string Value)> hostOutputs,
87+
Exception? exception,
88+
TimeSpan elapsedTime)
8189
{
8290
Debug.Assert(exception is null || (generatedSources.IsEmpty && diagnostics.Length == 1));
8391

@@ -86,6 +94,7 @@ internal GeneratorRunResult(ISourceGenerator generator, ImmutableArray<Generated
8694
this.Diagnostics = diagnostics;
8795
this.TrackedSteps = namedSteps;
8896
this.TrackedOutputSteps = outputSteps;
97+
this.HostOutputs = hostOutputs;
8998
this.Exception = exception;
9099
this.ElapsedTime = elapsedTime;
91100
}
@@ -109,6 +118,8 @@ internal GeneratorRunResult(ISourceGenerator generator, ImmutableArray<Generated
109118
/// </remarks>
110119
public ImmutableArray<Diagnostic> Diagnostics { get; }
111120

121+
internal ImmutableArray<(string Key, string Value)> HostOutputs { get; }
122+
112123
/// <summary>
113124
/// An <see cref="System.Exception"/> instance that was thrown by the generator, or <c>null</c> if the generator completed without error.
114125
/// </summary>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Immutable;
7+
using System.Threading;
8+
using Microsoft.CodeAnalysis.PooledObjects;
9+
10+
namespace Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler
11+
{
12+
internal static partial class GeneratorExtensions
13+
{
14+
public static void RegisterHostOutput<TSource>(ref this IncrementalGeneratorInitializationContext @this, IncrementalValuesProvider<TSource> source, Action<HostProductionContext, TSource, CancellationToken> action)
15+
{
16+
_ = @this;
17+
source.Node.RegisterOutput(new HostOutputNode<TSource>(source.Node, action));
18+
}
19+
20+
public static ImmutableArray<(string Key, string Value)> GetHostOutputs(this GeneratorRunResult runResult) => runResult.HostOutputs;
21+
}
22+
23+
internal readonly struct HostProductionContext
24+
{
25+
internal readonly ArrayBuilder<(string, string)> Outputs;
26+
27+
internal HostProductionContext(ArrayBuilder<(string, string)> outputs)
28+
{
29+
Outputs = outputs;
30+
}
31+
32+
public void AddOutput(string name, string value) => Outputs.Add((name, value));
33+
}
34+
}

0 commit comments

Comments
 (0)