Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<Sha>7e80445ee82adbf9a8e6ae601ac5e239d982afaa</Sha>
<SourceBuild RepoName="xliff-tasks" ManagedOnly="true" />
</Dependency>
<Dependency Name="Microsoft.SourceBuild.Intermediate.source-build" Version="0.1.0-alpha.1.21428.1">
<Dependency Name="Microsoft.SourceBuild.Intermediate.source-build" Version="0.1.0-alpha.1.21431.1">
<Uri>https://github.com/dotnet/source-build</Uri>
<Sha>32d7d9397b3dcf1d0633cbfae18f81812c90d562</Sha>
<Sha>5d62fad25fc5a0a3df5687cf309acd9a6d45f292</Sha>
<SourceBuild RepoName="source-build" ManagedOnly="true" />
</Dependency>
</ProductDependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ internal override SyntaxTree ParseGeneratedSourceText(GeneratedSourceText input,

internal override CommonMessageProvider MessageProvider => CSharp.MessageProvider.Instance;

internal override AdditionalSourcesCollection CreateSourcesCollection() => new AdditionalSourcesCollection(".cs");
internal override string SourceExtension => ".cs";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ public void Hint_Name_Must_Be_Unique(string hintName1, string hintName2)
Assert.Contains(hintName2, exception.Message);
}

[Fact]
public void Hint_Name_Must_Be_Unique_When_Combining_Soruces()
{
AdditionalSourcesCollection asc = new AdditionalSourcesCollection(".cs");
asc.Add("hintName1", SourceText.From("", Encoding.UTF8));
asc.Add("hintName2", SourceText.From("", Encoding.UTF8));

AdditionalSourcesCollection asc2 = new AdditionalSourcesCollection(".cs");
asc2.Add("hintName3", SourceText.From("", Encoding.UTF8));
asc2.Add("hintName1", SourceText.From("", Encoding.UTF8));

var exception = Assert.Throws<ArgumentException>("hintName", () => asc.CopyTo(asc2));
Assert.Contains("hintName1", exception.Message);
}

[Theory]
[InlineData("file.cs", "file.cs")]
[InlineData("file", "file")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ class C { }
);
}

[Fact(Skip = "https://github.com/dotnet/roslyn/issues/54185: the addition happens later so the exceptions don't occur directly at add-time. we should decide if this subtle behavior change is acceptable")]
[Fact]
public void Generator_HintName_MustBe_Unique()
{
var source = @"
Expand Down Expand Up @@ -485,6 +485,47 @@ class C { }
Assert.Equal(2, outputCompilation.SyntaxTrees.Count());
}

[ConditionalFact(typeof(MonoOrCoreClrOnly), Reason = "Desktop CLR displays argument exceptions differently")]
public void Generator_HintName_MustBe_Unique_Across_Outputs()
{
var source = @"
class C { }
";
var parseOptions = TestOptions.Regular.WithLanguageVersion(LanguageVersion.Preview);
Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions);
compilation.VerifyDiagnostics();
Assert.Single(compilation.SyntaxTrees);

var generator = new PipelineCallbackGenerator((ctx) =>
{
ctx.RegisterSourceOutput(ctx.CompilationProvider, (spc, c) =>
{
spc.AddSource("test", SourceText.From("public class D{}", Encoding.UTF8));

// throws immediately, because we're within the same output node
Assert.Throws<ArgumentException>("hintName", () => spc.AddSource("test", SourceText.From("public class D{}", Encoding.UTF8)));

// throws for .cs too
Assert.Throws<ArgumentException>("hintName", () => spc.AddSource("test.cs", SourceText.From("public class D{}", Encoding.UTF8)));
});

ctx.RegisterSourceOutput(ctx.CompilationProvider, (spc, c) =>
{
// will not throw at this point, because we have no way of knowing what the other outputs added
// we *will* throw later in the driver when we combine them however (this is a change for V2, but not visible from V1)
spc.AddSource("test", SourceText.From("public class D{}", Encoding.UTF8));
});
});

GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: parseOptions);
driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics);
outputCompilation.VerifyDiagnostics();
generatorDiagnostics.Verify(
Diagnostic("CS8785").WithArguments("PipelineCallbackGenerator", "ArgumentException", "The hintName 'test.cs' of the added source file must be unique within a generator. (Parameter 'hintName')").WithLocation(1, 1)
);
Assert.Equal(1, outputCompilation.SyntaxTrees.Count());
}

[Fact]
public void Generator_HintName_Is_Appended_With_GeneratorName()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,27 @@ public bool Contains(string hintName)
return false;
}

public void CopyTo(AdditionalSourcesCollection asc)
{
// we know the individual hint names are valid, but we do need to check that they
// don't collide with any we already have
if (asc._sourcesAdded.Count == 0)
{
asc._sourcesAdded.AddRange(this._sourcesAdded);
}
else
{
foreach (var source in this._sourcesAdded)
{
if (asc.Contains(source.HintName))
{
throw new ArgumentException(string.Format(CodeAnalysisResources.HintNameUniquePerGenerator, source.HintName), "hintName");
}
asc._sourcesAdded.Add(source);
}
}
}

internal ImmutableArray<GeneratedSourceText> ToImmutableAndFree() => _sourcesAdded.ToImmutableAndFree();

internal ImmutableArray<GeneratedSourceText> ToImmutable() => _sourcesAdded.ToImmutable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ namespace Microsoft.CodeAnalysis
/// </summary>
internal sealed class SourceGeneratorAdaptor : IIncrementalGenerator
{
private readonly string _sourceExtension;

internal ISourceGenerator SourceGenerator { get; }

public SourceGeneratorAdaptor(ISourceGenerator generator)
public SourceGeneratorAdaptor(ISourceGenerator generator, string sourceExtension)
{
SourceGenerator = generator;
_sourceExtension = sourceExtension;
}

public void Initialize(IncrementalGeneratorInitializationContext context)
Expand Down Expand Up @@ -48,7 +51,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

context.RegisterSourceOutput(contextBuilderSource, (productionContext, contextBuilder) =>
{
var generatorExecutionContext = contextBuilder.ToExecutionContext(productionContext.CancellationToken);
var generatorExecutionContext = contextBuilder.ToExecutionContext(_sourceExtension, productionContext.CancellationToken);
SourceGenerator.Execute(generatorExecutionContext);

// copy the contents of the old context to the new
Expand All @@ -67,10 +70,10 @@ internal record GeneratorContextBuilder(Compilation Compilation)

public ISyntaxContextReceiver? Receiver;

public GeneratorExecutionContext ToExecutionContext(CancellationToken cancellationToken)
public GeneratorExecutionContext ToExecutionContext(string sourceExtension, CancellationToken cancellationToken)
{
Debug.Assert(ParseOptions is object && ConfigOptions is object);
return new GeneratorExecutionContext(Compilation, ParseOptions, AdditionalTexts, ConfigOptions, Receiver, cancellationToken);
return new GeneratorExecutionContext(Compilation, ParseOptions, AdditionalTexts, ConfigOptions, Receiver, sourceExtension, cancellationToken);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ public readonly struct GeneratorExecutionContext
{
private readonly DiagnosticBag _diagnostics;

private readonly ArrayBuilder<GeneratedSourceText> _additionalSources;
private readonly AdditionalSourcesCollection _additionalSources;

internal GeneratorExecutionContext(Compilation compilation, ParseOptions parseOptions, ImmutableArray<AdditionalText> additionalTexts, AnalyzerConfigOptionsProvider optionsProvider, ISyntaxContextReceiver? syntaxReceiver, CancellationToken cancellationToken = default)
internal GeneratorExecutionContext(Compilation compilation, ParseOptions parseOptions, ImmutableArray<AdditionalText> additionalTexts, AnalyzerConfigOptionsProvider optionsProvider, ISyntaxContextReceiver? syntaxReceiver, string sourceExtension, CancellationToken cancellationToken = default)
{
Compilation = compilation;
ParseOptions = parseOptions;
Expand All @@ -29,7 +29,7 @@ internal GeneratorExecutionContext(Compilation compilation, ParseOptions parseOp
SyntaxReceiver = (syntaxReceiver as SyntaxContextReceiverAdaptor)?.Receiver;
SyntaxContextReceiver = (syntaxReceiver is SyntaxContextReceiverAdaptor) ? null : syntaxReceiver;
CancellationToken = cancellationToken;
_additionalSources = ArrayBuilder<GeneratedSourceText>.GetInstance();
_additionalSources = new AdditionalSourcesCollection(sourceExtension);
_diagnostics = new DiagnosticBag();
}

Expand Down Expand Up @@ -85,7 +85,7 @@ internal GeneratorExecutionContext(Compilation compilation, ParseOptions parseOp
/// </summary>
/// <param name="hintName">An identifier that can be used to reference this source text, must be unique within this generator</param>
/// <param name="sourceText">The <see cref="SourceText"/> to add to the compilation</param>
public void AddSource(string hintName, SourceText sourceText) => _additionalSources.Add(new GeneratedSourceText(hintName, sourceText));
public void AddSource(string hintName, SourceText sourceText) => _additionalSources.Add(hintName, sourceText);

/// <summary>
/// Adds a <see cref="Diagnostic"/> to the users compilation
Expand All @@ -107,7 +107,7 @@ internal void Free()

internal void CopyToProductionContext(SourceProductionContext ctx)
{
ctx.Sources.AddRange(_additionalSources);
_additionalSources.CopyTo(ctx.Sources);
ctx.Diagnostics.AddRange(_diagnostics);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal GeneratorDriver(GeneratorDriverState state)

internal GeneratorDriver(ParseOptions parseOptions, ImmutableArray<ISourceGenerator> generators, AnalyzerConfigOptionsProvider optionsProvider, ImmutableArray<AdditionalText> additionalTexts, GeneratorDriverOptions driverOptions)
{
(var filteredGenerators, var incrementalGenerators) = GetIncrementalGenerators(generators);
(var filteredGenerators, var incrementalGenerators) = GetIncrementalGenerators(generators, SourceExtension);
_state = new GeneratorDriverState(parseOptions, optionsProvider, filteredGenerators, incrementalGenerators, additionalTexts, ImmutableArray.Create(new GeneratorState[filteredGenerators.Length]), DriverStateTable.Empty, driverOptions.DisabledOutputs);
}

Expand Down Expand Up @@ -66,7 +66,7 @@ public GeneratorDriver RunGeneratorsAndUpdateCompilation(Compilation compilation

public GeneratorDriver AddGenerators(ImmutableArray<ISourceGenerator> generators)
{
(var filteredGenerators, var incrementalGenerators) = GetIncrementalGenerators(generators);
(var filteredGenerators, var incrementalGenerators) = GetIncrementalGenerators(generators, SourceExtension);
var newState = _state.With(sourceGenerators: _state.Generators.AddRange(filteredGenerators),
incrementalGenerators: _state.IncrementalGenerators.AddRange(incrementalGenerators),
generatorStates: _state.GeneratorStates.AddRange(new GeneratorState[filteredGenerators.Length]));
Expand Down Expand Up @@ -179,7 +179,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos
var outputBuilder = ArrayBuilder<IIncrementalGeneratorOutputNode>.GetInstance();
var inputBuilder = ArrayBuilder<ISyntaxInputNode>.GetInstance();
var postInitSources = ImmutableArray<GeneratedSyntaxTree>.Empty;
var pipelineContext = new IncrementalGeneratorInitializationContext(inputBuilder, outputBuilder);
var pipelineContext = new IncrementalGeneratorInitializationContext(inputBuilder, outputBuilder, SourceExtension);

Exception? ex = null;
try
Expand Down Expand Up @@ -265,7 +265,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos
private IncrementalExecutionContext UpdateOutputs(ImmutableArray<IIncrementalGeneratorOutputNode> outputNodes, IncrementalGeneratorOutputKind outputKind, CancellationToken cancellationToken, DriverStateTable.Builder? driverStateBuilder = null)
{
Debug.Assert(outputKind != IncrementalGeneratorOutputKind.None);
IncrementalExecutionContext context = new IncrementalExecutionContext(driverStateBuilder, CreateSourcesCollection());
IncrementalExecutionContext context = new IncrementalExecutionContext(driverStateBuilder, new AdditionalSourcesCollection(SourceExtension));
foreach (var outputNode in outputNodes)
{
// if we're looking for this output kind, and it has not been explicitly disabled
Expand Down Expand Up @@ -337,13 +337,13 @@ internal static string GetFilePathPrefixForGenerator(ISourceGenerator generator)
return Path.Combine(type.Assembly.GetName().Name ?? string.Empty, type.FullName!);
}

private static (ImmutableArray<ISourceGenerator>, ImmutableArray<IIncrementalGenerator>) GetIncrementalGenerators(ImmutableArray<ISourceGenerator> generators)
private static (ImmutableArray<ISourceGenerator>, ImmutableArray<IIncrementalGenerator>) GetIncrementalGenerators(ImmutableArray<ISourceGenerator> generators, string sourceExtension)
{
return (generators, generators.SelectAsArray(g => g switch
{
IncrementalGeneratorWrapper igw => igw.Generator,
IIncrementalGenerator ig => ig,
_ => new SourceGeneratorAdaptor(g)
_ => new SourceGeneratorAdaptor(g, sourceExtension)
}));

}
Expand All @@ -354,6 +354,6 @@ private static (ImmutableArray<ISourceGenerator>, ImmutableArray<IIncrementalGen

internal abstract SyntaxTree ParseGeneratedSourceText(GeneratedSourceText input, string fileName, CancellationToken cancellationToken);

internal abstract AdditionalSourcesCollection CreateSourcesCollection();
internal abstract string SourceExtension { get; }
}
}
Loading