|
9 | 9 | using System.Text; |
10 | 10 | using System.Threading; |
11 | 11 | using System.Threading.Tasks; |
12 | | - using CodeGeneration.Roslyn.Engine; |
13 | | - using global::CodeGeneration.Roslyn; |
14 | 12 | using ImmutableObjectGraph.Generation.Roslyn; |
15 | 13 | using Microsoft.CodeAnalysis; |
16 | 14 | using Microsoft.CodeAnalysis.CSharp; |
@@ -38,7 +36,6 @@ public CodeGenTests(ITestOutputHelper logger) |
38 | 36 | .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) |
39 | 37 | .AddMetadataReferences(GetNetStandard20References()) |
40 | 38 | .AddMetadataReference(MetadataReference.CreateFromFile(typeof(GenerateImmutableAttribute).Assembly.Location)) |
41 | | - .AddMetadataReference(MetadataReference.CreateFromFile(typeof(CodeGenerationAttributeAttribute).Assembly.Location)) |
42 | 39 | .AddMetadataReference(MetadataReference.CreateFromFile(typeof(Optional).Assembly.Location)) |
43 | 40 | .AddMetadataReference(MetadataReference.CreateFromFile(typeof(ImmutableArray).Assembly.Location)); |
44 | 41 | var inputDocument = project.AddDocument("input.cs", string.Empty); |
@@ -265,40 +262,49 @@ protected async Task<GenerationResult> GenerateAsync(SourceText inputSource) |
265 | 262 | { |
266 | 263 | var solution = this.solution.WithDocumentText(this.inputDocumentId, inputSource); |
267 | 264 | var inputDocument = solution.GetDocument(this.inputDocumentId); |
268 | | - var generatorDiagnostics = new List<Diagnostic>(); |
269 | | - var progress = new SynchronousProgress<Diagnostic>(generatorDiagnostics.Add); |
270 | 265 | var inputCompilation = (CSharpCompilation)await inputDocument.Project.GetCompilationAsync(); |
271 | | - var inputSyntaxTree = await inputDocument.GetSyntaxTreeAsync(); |
272 | | - var outputSyntaxTree = await DocumentTransform.TransformAsync(inputCompilation, inputSyntaxTree, null, Assembly.Load, progress); |
273 | | - var outputDocument = inputDocument.Project |
274 | | - .AddDocument("output.cs", outputSyntaxTree.GetRoot()); |
275 | | - |
276 | | - // Make sure the result compiles without errors or warnings. |
277 | | - var compilation = await outputDocument.Project.GetCompilationAsync(); |
278 | | - var compilationDiagnostics = compilation.GetDiagnostics(); |
| 266 | + var driver = CSharpGeneratorDriver.Create(new CodeGenerator()); |
| 267 | + var runResult = driver.RunGenerators(inputCompilation).GetRunResult(); |
| 268 | + var generatorDiagnostics = runResult.Diagnostics; |
| 269 | + var project = inputDocument.Project; |
| 270 | + |
| 271 | + var i = 0; |
| 272 | + var syntaxTrees = ImmutableArray.CreateBuilder<SyntaxTree>(); |
| 273 | + foreach (var t in runResult.GeneratedTrees) |
| 274 | + { |
| 275 | + var document = project.AddDocument($"output{i++}.cs", t.GetRoot()); |
279 | 276 |
|
280 | | - SourceText outputDocumentText = await outputDocument.GetTextAsync(); |
281 | | - this.logger.WriteLine("{0}", outputDocumentText); |
| 277 | + SourceText outputDocumentText = await document.GetTextAsync(); |
| 278 | + this.logger.WriteLine("{0}", outputDocumentText); |
282 | 279 |
|
283 | | - // Verify all line endings are consistent (otherwise VS can bug the heck out of the user if they have the generated file open). |
284 | | - string firstLineEnding = null; |
285 | | - foreach (var line in outputDocumentText.Lines) |
286 | | - { |
287 | | - string actualNewLine = line.Text.GetSubText(TextSpan.FromBounds(line.End, line.EndIncludingLineBreak)).ToString(); |
288 | | - if (firstLineEnding == null) |
289 | | - { |
290 | | - firstLineEnding = actualNewLine; |
291 | | - } |
292 | | - else if (actualNewLine != firstLineEnding && actualNewLine.Length > 0) |
| 280 | + // Verify all line endings are consistent (otherwise VS can bug the heck out of the user if they have the generated file open). |
| 281 | + string firstLineEnding = null; |
| 282 | + foreach (var line in outputDocumentText.Lines) |
293 | 283 | { |
294 | | - string expected = EscapeLineEndingCharacters(firstLineEnding); |
295 | | - string actual = EscapeLineEndingCharacters(actualNewLine); |
296 | | - Assert.True(false, $"Expected line ending characters '{expected}' but found '{actual}' on line {line.LineNumber + 1}.\nContent: {line}"); |
| 284 | + string actualNewLine = line.Text.GetSubText(TextSpan.FromBounds(line.End, line.EndIncludingLineBreak)).ToString(); |
| 285 | + if (firstLineEnding == null) |
| 286 | + { |
| 287 | + firstLineEnding = actualNewLine; |
| 288 | + } |
| 289 | + else if (actualNewLine != firstLineEnding && actualNewLine.Length > 0) |
| 290 | + { |
| 291 | + string expected = EscapeLineEndingCharacters(firstLineEnding); |
| 292 | + string actual = EscapeLineEndingCharacters(actualNewLine); |
| 293 | + Assert.True(false, $"Expected line ending characters '{expected}' but found '{actual}' on line {line.LineNumber + 1}.\nContent: {line}"); |
| 294 | + } |
297 | 295 | } |
| 296 | + |
| 297 | + var syntaxTree = await document.GetSyntaxTreeAsync(); |
| 298 | + syntaxTrees.Add(syntaxTree); |
| 299 | + |
| 300 | + project = document.Project; |
298 | 301 | } |
299 | 302 |
|
300 | | - var semanticModel = await outputDocument.GetSemanticModelAsync(); |
301 | | - var result = new GenerationResult(outputDocument, semanticModel, generatorDiagnostics, compilationDiagnostics); |
| 303 | + // Make sure the result compiles without errors or warnings. |
| 304 | + var compilation = await project.GetCompilationAsync(); |
| 305 | + var compilationDiagnostics = compilation.GetDiagnostics(); |
| 306 | + |
| 307 | + var result = new GenerationResult(compilation, syntaxTrees.ToImmutable(), generatorDiagnostics, compilationDiagnostics); |
302 | 308 |
|
303 | 309 | foreach (var diagnostic in generatorDiagnostics) |
304 | 310 | { |
@@ -338,32 +344,39 @@ private static string EscapeLineEndingCharacters(string whitespace) |
338 | 344 |
|
339 | 345 | private static IEnumerable<MetadataReference> GetNetStandard20References() |
340 | 346 | { |
341 | | - string nugetPackageRoot = Environment.GetEnvironmentVariable("NUGET_PACKAGES") ?? Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\.nuget\packages"); |
342 | | - string netstandardRoot = Path.Combine(nugetPackageRoot, @"netstandard.library\2.0.3\build\netstandard2.0\ref"); |
343 | | - foreach (string assembly in Directory.GetFiles(netstandardRoot, "*.dll")) |
| 347 | + var nugetPackageRoot = Environment.GetEnvironmentVariable("NUGET_PACKAGES") ?? Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\.nuget\packages"); |
| 348 | + foreach (var dir in Directory.GetDirectories(Path.Combine(nugetPackageRoot, "netstandard.library"), "2.*")) |
344 | 349 | { |
345 | | - yield return MetadataReference.CreateFromFile(assembly); |
| 350 | + var netstandardRoot = Path.Combine(dir, @"build\netstandard2.0\ref"); |
| 351 | + foreach (string assembly in Directory.GetFiles(netstandardRoot, "*.dll")) |
| 352 | + { |
| 353 | + yield return MetadataReference.CreateFromFile(assembly); |
| 354 | + } |
| 355 | + break; |
346 | 356 | } |
347 | 357 | } |
348 | 358 |
|
349 | 359 | protected class GenerationResult |
350 | 360 | { |
351 | 361 | public GenerationResult( |
352 | | - Document document, |
353 | | - SemanticModel semanticModel, |
| 362 | + Compilation compilation, |
| 363 | + ImmutableArray<SyntaxTree> syntaxTrees, |
354 | 364 | IReadOnlyList<Diagnostic> generatorDiagnostics, |
355 | 365 | IReadOnlyList<Diagnostic> compilationDiagnostics) |
356 | 366 | { |
357 | | - this.Document = document; |
358 | | - this.SemanticModel = semanticModel; |
359 | | - this.Declarations = CSharpDeclarationComputer.GetDeclarationsInSpan(semanticModel, TextSpan.FromBounds(0, semanticModel.SyntaxTree.Length), true, CancellationToken.None); |
| 367 | + this.Compilation = compilation; |
| 368 | + this.SyntaxTrees = syntaxTrees; |
| 369 | + this.SemanticModels = syntaxTrees.Select(s => compilation.GetSemanticModel(s)).ToImmutableArray(); |
| 370 | + this.Declarations = SemanticModels.SelectMany(semanticModel => CSharpDeclarationComputer.GetDeclarationsInSpan(semanticModel, TextSpan.FromBounds(0, semanticModel.SyntaxTree.Length), true, CancellationToken.None)).ToImmutableArray(); |
360 | 371 | this.GeneratorDiagnostics = generatorDiagnostics; |
361 | 372 | this.CompilationDiagnostics = compilationDiagnostics; |
362 | 373 | } |
363 | 374 |
|
364 | | - public Document Document { get; private set; } |
| 375 | + public Compilation Compilation { get; } |
| 376 | + |
| 377 | + public ImmutableArray<SemanticModel> SemanticModels { get; private set; } |
365 | 378 |
|
366 | | - public SemanticModel SemanticModel { get; private set; } |
| 379 | + public ImmutableArray<SyntaxTree> SyntaxTrees { get; } |
367 | 380 |
|
368 | 381 | internal ImmutableArray<DeclarationInfo> Declarations { get; private set; } |
369 | 382 |
|
|
0 commit comments