public void ParseOptions_Are_Passed_To_Generator() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); ParseOptions?passedOptions = null; var testGenerator = new CallbackGenerator( onInit: (i) => { }, onExecute: (e) => { passedOptions = e.ParseOptions; } ); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out _, out _); Assert.Same(parseOptions, passedOptions); }
public void Single_File_Is_Added() { var source = @" class C { } "; var generatorSource = @" class GeneratedClass { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); SingleFileTestGenerator testGenerator = new SingleFileTestGenerator(generatorSource); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out _); Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); Assert.NotEqual(compilation, outputCompilation); }
public void User_Source_Can_Depend_On_Generated_Source() { var source = @" #pragma warning disable CS0649 class C { public D d; } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics( // (5,12): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?) // public D d; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("D").WithLocation(5, 12) ); Assert.Single(compilation.SyntaxTrees); var generator = new SingleFileTestGenerator("public class D { }"); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); outputCompilation.VerifyDiagnostics(); generatorDiagnostics.Verify(); }
public void Generator_HintName_Is_Appended_With_GeneratorName() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var generator = new SingleFileTestGenerator("public class D {}", "source.cs"); var generator2 = new SingleFileTestGenerator2("public class E {}", "source.cs"); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator, generator2), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); outputCompilation.VerifyDiagnostics(); generatorDiagnostics.Verify(); Assert.Equal(3, outputCompilation.SyntaxTrees.Count()); var filePaths = outputCompilation.SyntaxTrees.Skip(1).Select(t => t.FilePath).ToArray(); Assert.Equal(new[] { $"{generator.GetType().Module.ModuleVersionId}_{generator.GetType().FullName}_source.cs", $"{generator2.GetType().Module.ModuleVersionId}_{generator2.GetType().FullName}_source.cs" }, filePaths); }
public void FullGeneration_Diagnostics_AreSame_As_RunResults() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); string description = "This is a test diagnostic"; DiagnosticDescriptor generatorDiagnostic1 = new DiagnosticDescriptor("TG001", "Test Diagnostic", description, "Generators", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: description); DiagnosticDescriptor generatorDiagnostic2 = new DiagnosticDescriptor("TG002", "Test Diagnostic", description, "Generators", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: description); DiagnosticDescriptor generatorDiagnostic3 = new DiagnosticDescriptor("TG003", "Test Diagnostic", description, "Generators", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: description); var diagnostic1 = Microsoft.CodeAnalysis.Diagnostic.Create(generatorDiagnostic1, Location.None); var diagnostic2 = Microsoft.CodeAnalysis.Diagnostic.Create(generatorDiagnostic2, Location.None); var diagnostic3 = Microsoft.CodeAnalysis.Diagnostic.Create(generatorDiagnostic3, Location.None); var generator = new CallbackGenerator((ic) => { }, (sgc) => { sgc.ReportDiagnostic(diagnostic1); sgc.ReportDiagnostic(diagnostic2); }); var generator2 = new CallbackGenerator2((ic) => { }, (sgc) => { sgc.ReportDiagnostic(diagnostic3); }); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator, generator2), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver = driver.RunFullGeneration(compilation, out _, out var fullDiagnostics); var results = driver.GetRunResult(); Assert.Equal(3, results.Diagnostics.Length); Assert.Equal(3, fullDiagnostics.Length); AssertEx.Equal(results.Diagnostics, fullDiagnostics); }
public void Generator_Can_Report_Diagnostics() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); string description = "This is a test diagnostic"; DiagnosticDescriptor generatorDiagnostic = new DiagnosticDescriptor("TG001", "Test Diagnostic", description, "Generators", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: description); var diagnostic = Microsoft.CodeAnalysis.Diagnostic.Create(generatorDiagnostic, Location.None); var generator = new CallbackGenerator((ic) => { }, (sgc) => sgc.ReportDiagnostic(diagnostic)); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); outputCompilation.VerifyDiagnostics(); generatorDiagnostics.Verify( Diagnostic("TG001").WithLocation(1, 1) ); }
public void Generator_HintName_MustBe_Unique() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var generator = new CallbackGenerator((ic) => { }, (sgc) => { sgc.AddSource("test", SourceText.From("public class D{}", Encoding.UTF8)); // the assert should swallow the exception, so we'll actually successfully generate Assert.Throws <ArgumentException>("hintName", () => sgc.AddSource("test", SourceText.From("public class D{}", Encoding.UTF8))); // also throws for <name> vs <name>.cs Assert.Throws <ArgumentException>("hintName", () => sgc.AddSource("test.cs", SourceText.From("public class D{}", Encoding.UTF8))); }); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); outputCompilation.VerifyDiagnostics(); generatorDiagnostics.Verify(); Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); }
public void Error_During_Generation_Does_Not_Affect_Other_Generators() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var exception = new InvalidOperationException("generate error"); var generator = new CallbackGenerator((ic) => { }, (sgc) => throw exception); var generator2 = new CallbackGenerator2((ic) => { }, (sgc) => { }, source: "public class D { }"); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator, generator2), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); outputCompilation.VerifyDiagnostics(); Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); generatorDiagnostics.Verify( // warning CS8785: Generator 'CallbackGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was 'InvalidOperationException' with message 'generate error' Diagnostic("CS" + (int)ErrorCode.WRN_GeneratorFailedDuringGeneration).WithArguments("CallbackGenerator", "InvalidOperationException", "generate error").WithLocation(1, 1) ); }
public void Error_During_Generation_Has_Exception_In_Description() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var exception = new InvalidOperationException("generate error"); var generator = new CallbackGenerator((ic) => { }, (sgc) => throw exception); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); outputCompilation.VerifyDiagnostics(); Assert.EndsWith(exception.ToString() + "'.", generatorDiagnostics.Single().Descriptor.Description.ToString()); }
public void Added_Additional_File() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); AdditionalFileAddedGenerator testGenerator = new AdditionalFileAddedGenerator(); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); // run initial generation pass driver = driver.RunFullGeneration(compilation, out var outputCompilation, out _); Assert.Single(outputCompilation.SyntaxTrees); // create an edit AdditionalFileAddedEdit edit = new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file1.cs", "")); driver = driver.WithPendingEdits(ImmutableArray.Create <PendingEdit>(edit)); // now try apply edits driver = driver.TryApplyEdits(compilation, out outputCompilation, out var succeeded); Assert.True(succeeded); Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); }
public void Failed_Edit_Does_Not_Change_Compilation() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); AdditionalFileAddedGenerator testGenerator = new AdditionalFileAddedGenerator() { CanApplyChanges = false }; GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out _); Assert.Single(outputCompilation.SyntaxTrees); // create an edit AdditionalFileAddedEdit edit = new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file2.cs", "")); driver = driver.WithPendingEdits(ImmutableArray.Create <PendingEdit>(edit)); // now try apply edits (which will fail) driver = driver.TryApplyEdits(compilation, out var editedCompilation, out var succeeded); Assert.False(succeeded); Assert.Single(editedCompilation.SyntaxTrees); Assert.Equal(compilation, editedCompilation); }
public void TryApply_Edits_Does_Nothing_When_Nothing_Pending() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); AdditionalFileAddedGenerator testGenerator = new AdditionalFileAddedGenerator(); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); // run an initial generation pass driver = driver.RunFullGeneration(compilation, out var outputCompilation, out _); Assert.Single(outputCompilation.SyntaxTrees); // now try apply edits (which should succeed, but do nothing) driver = driver.TryApplyEdits(compilation, out var editedCompilation, out var succeeded); Assert.True(succeeded); Assert.Equal(outputCompilation, editedCompilation); }
public static ImmutableArray <Diagnostic> RunGenerator(string source) { var syntaxTree = CSharpSyntaxTree.ParseText(SourceText.From(source, Encoding.UTF8)); //var parseOptions = TestOptions.Regular; var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithOptimizationLevel(OptimizationLevel.Debug) .WithGeneralDiagnosticOption(ReportDiagnostic.Default); var references = new MetadataReference[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(GenerateAutomaticInterfaceAttribute).Assembly.Location), MetadataReference.CreateFromFile(Assembly.Load("netstandard, Version=2.0.0.0").Location), MetadataReference.CreateFromFile(Assembly.Load("System.Runtime, Version=4.2.2.0").Location) }; Compilation compilation = CSharpCompilation.Create("testgenerator", new[] { syntaxTree }, references, compilationOptions).WithReferences(references); var diagnostics = compilation.GetDiagnostics(); if (!VerifyDiagnostics(diagnostics, new[] { "CS0012", "CS0616", "CS0246" })) { // this will make the test fail, check the input source code! return(diagnostics); } var generator = new AutomaticInterfaceGenerator(); var parseOptions = syntaxTree.Options as CSharpParseOptions; GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), null, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); return(generatorDiagnostics); }
public void Added_Additional_File_With_Full_Generation() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); AdditionalFileAddedGenerator testGenerator = new AdditionalFileAddedGenerator(); var text = new InMemoryAdditionalText("a\\file1.cs", ""); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, generators: ImmutableArray.Create <ISourceGenerator>(testGenerator), optionsProvider: CompilerAnalyzerConfigOptionsProvider.Empty, additionalTexts: ImmutableArray.Create <AdditionalText>(new InMemoryAdditionalText("a\\file1.cs", ""))); driver = driver.RunFullGeneration(compilation, out var outputCompilation, out _); // we should have a single extra file for the additional texts Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); // even if we run a full gen, or partial, nothing should change yet driver = driver.TryApplyEdits(outputCompilation, out var editedCompilation, out var succeeded); Assert.True(succeeded); Assert.Equal(2, editedCompilation.SyntaxTrees.Count()); driver = driver.RunFullGeneration(compilation, out outputCompilation, out _); Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); // create an edit AdditionalFileAddedEdit edit = new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file2.cs", "")); driver = driver.WithPendingEdits(ImmutableArray.Create <PendingEdit>(edit)); // now try apply edits driver = driver.TryApplyEdits(compilation, out editedCompilation, out succeeded); Assert.True(succeeded); Assert.Equal(3, editedCompilation.SyntaxTrees.Count()); // if we run a full compilation again, we should still get 3 syntax trees driver = driver.RunFullGeneration(compilation, out outputCompilation, out _); Assert.Equal(3, outputCompilation.SyntaxTrees.Count()); }
public void Multiple_Added_Additional_Files() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); AdditionalFileAddedGenerator testGenerator = new AdditionalFileAddedGenerator(); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, generators: ImmutableArray.Create <ISourceGenerator>(testGenerator), additionalTexts: ImmutableArray.Create <AdditionalText>(new InMemoryAdditionalText("a\\file1.cs", ""))); // run initial generation pass driver = driver.RunFullGeneration(compilation, out var outputCompilation, out _); Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); // create an edit AdditionalFileAddedEdit edit = new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file2.cs", "")); driver = driver.WithPendingEdits(ImmutableArray.Create <PendingEdit>(edit)); // now try apply edits driver = driver.TryApplyEdits(compilation, out var editedCompilation, out var succeeded); Assert.True(succeeded); Assert.Equal(3, editedCompilation.SyntaxTrees.Count()); // if we run a full compilation again, we should still get 3 syntax trees driver = driver.RunFullGeneration(compilation, out outputCompilation, out _); Assert.Equal(3, outputCompilation.SyntaxTrees.Count()); // lets add multiple edits driver = driver.WithPendingEdits(ImmutableArray.Create <PendingEdit>(new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file3.cs", "")), new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file4.cs", "")), new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file5.cs", "")))); // now try apply edits driver = driver.TryApplyEdits(compilation, out editedCompilation, out succeeded); Assert.True(succeeded); Assert.Equal(6, editedCompilation.SyntaxTrees.Count()); }
public void Adding_Another_Generator_Makes_TryApplyEdits_Fail() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); SingleFileTestGenerator testGenerator1 = new SingleFileTestGenerator("public class D { }"); SingleFileTestGenerator2 testGenerator2 = new SingleFileTestGenerator2("public class E { }"); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, generators: ImmutableArray.Create <ISourceGenerator>(testGenerator1), optionsProvider: CompilerAnalyzerConfigOptionsProvider.Empty, additionalTexts: ImmutableArray <AdditionalText> .Empty); driver = driver.RunFullGeneration(compilation, out var outputCompilation, out _); Assert.Equal(2, outputCompilation.SyntaxTrees.Count()); // try apply edits driver = driver.TryApplyEdits(compilation, out _, out bool success); Assert.True(success); // add another generator driver = driver.AddGenerators(ImmutableArray.Create <ISourceGenerator>(testGenerator2)); // try apply changes should now fail driver = driver.TryApplyEdits(compilation, out _, out success); Assert.False(success); // full generation driver = driver.RunFullGeneration(compilation, out outputCompilation, out _); Assert.Equal(3, outputCompilation.SyntaxTrees.Count()); // try apply changes should now succeed driver.TryApplyEdits(compilation, out _, out success); Assert.True(success); }
public void Generator_Is_Only_Initialized_Once() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); int initCount = 0, executeCount = 0; var generator = new CallbackGenerator((ic) => initCount++, (sgc) => executeCount++, source: "public class C { }"); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver = driver.RunFullGeneration(compilation, out var outputCompilation, out _); driver = driver.RunFullGeneration(outputCompilation, out outputCompilation, out _); driver.RunFullGeneration(outputCompilation, out outputCompilation, out _); Assert.Equal(1, initCount); Assert.Equal(3, executeCount); }
public static string GenerateCode(string code, ISourceGenerator sourceGenerator) { Compilation compilation = CSharpCompilation.Create(RandomUtils.NewName(), new[] { SyntaxFactory.ParseSyntaxTree(SourceText.From(code, Encoding.UTF8), Regular, "") }, References, DebugDll); GeneratorDriver driver = new CSharpGeneratorDriver(Regular, ImmutableArray.Create(sourceGenerator), ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var diagnostics); var array = outputCompilation.SyntaxTrees.ToArray(); Assert.Equal(2, array.Length); return(array[1].ToString()); }
public void Syntax_Receiver_Exception_During_Visit() { var source = @" class C { int Property { get; set; } void Function() { var x = 5; x += 4; } } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var exception = new Exception("Test Exception"); var testGenerator = new CallbackGenerator( onInit: (i) => i.RegisterForSyntaxNotifications(() => new TestSyntaxReceiver(tag: 0, callback: (a) => { if (a is AssignmentExpressionSyntax) { throw exception; } })), onExecute: (e) => { e.AddSource("test", SourceText.From("public class D{}", Encoding.UTF8)); } ); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver = driver.RunFullGeneration(compilation, out var outputCompilation, out var outputDiagnostics); var results = driver.GetRunResult(); Assert.Empty(results.GeneratedTrees); Assert.Single(results.Diagnostics); Assert.Single(results.Results); Assert.Single(results.Results[0].Diagnostics); Assert.NotNull(results.Results[0].Exception); Assert.Equal("Test Exception", results.Results[0].Exception?.Message); outputDiagnostics.Verify( Diagnostic("CS" + (int)ErrorCode.WRN_GeneratorFailedDuringGeneration).WithArguments("CallbackGenerator", "Exception", "Test Exception").WithLocation(1, 1) ); }
public void Syntax_Receiver_Exception_During_Visit_Stops_Visits_On_Other_Trees() { var source1 = @" class C { int Property { get; set; } } "; var source2 = @" class D { public void Method() { } } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Equal(2, compilation.SyntaxTrees.Count()); TestSyntaxReceiver receiver1 = new TestSyntaxReceiver(tag: 0, callback: (a) => { if (a is PropertyDeclarationSyntax) { throw new Exception("Test Exception"); } }); var testGenerator1 = new CallbackGenerator( onInit: (i) => i.RegisterForSyntaxNotifications(() => receiver1), onExecute: (e) => { } ); TestSyntaxReceiver receiver2 = new TestSyntaxReceiver(tag: 1); var testGenerator2 = new CallbackGenerator2( onInit: (i) => i.RegisterForSyntaxNotifications(() => receiver2), onExecute: (e) => { } ); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator1, testGenerator2), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver = driver.RunFullGeneration(compilation, out var outputCompilation, out var outputDiagnostics); var results = driver.GetRunResult(); Assert.DoesNotContain(receiver1.VisitedNodes, n => n is MethodDeclarationSyntax); Assert.Contains(receiver2.VisitedNodes, n => n is MethodDeclarationSyntax); }
public void Syntax_Receiver_Exception_During_Creation() { var source = @" class C { int Property { get; set; } void Function() { var x = 5; x += 4; } } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var testGenerator = new CallbackGenerator( onInit: (i) => i.RegisterForSyntaxNotifications(() => throw new Exception("Test Exception")), onExecute: (e) => { Assert.True(false); } ); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver = driver.RunFullGeneration(compilation, out var outputCompilation, out var outputDiagnostics); var results = driver.GetRunResult(); Assert.Empty(results.GeneratedTrees); Assert.Single(results.Diagnostics); Assert.Single(results.Results); Assert.Single(results.Results[0].Diagnostics); Assert.NotNull(results.Results[0].Exception); Assert.Equal("Test Exception", results.Results[0].Exception?.Message); outputDiagnostics.Verify( Diagnostic(ErrorCode.WRN_GeneratorFailedDuringGeneration).WithArguments("CallbackGenerator").WithLocation(1, 1) ); }
public void Running_With_No_Changes_Is_NoOp() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray <ISourceGenerator> .Empty, CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var diagnostics); Assert.Empty(diagnostics); Assert.Single(outputCompilation.SyntaxTrees); Assert.Equal(compilation, outputCompilation); }
public void Error_During_Initialization_Generator_Does_Not_Run() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var exception = new InvalidOperationException("init error"); var generator = new CallbackGenerator((ic) => throw exception, (sgc) => { }, source: "class D { }"); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out _); Assert.Single(outputCompilation.SyntaxTrees); }
public void Syntax_Receiver_Visits_Syntax_In_Compilation() { var source = @" class C { int Property { get; set; } void Function() { var x = 5; x += 4; } } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); ISyntaxReceiver?receiver = null; var testGenerator = new CallbackGenerator( onInit: (i) => i.RegisterForSyntaxNotifications(() => new TestSyntaxReceiver()), onExecute: (e) => receiver = e.SyntaxReceiver ); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out _, out _); Assert.NotNull(receiver); Assert.IsType <TestSyntaxReceiver>(receiver); TestSyntaxReceiver testReceiver = (TestSyntaxReceiver)receiver !; Assert.Equal(21, testReceiver.VisitedNodes.Count); Assert.IsType <CompilationUnitSyntax>(testReceiver.VisitedNodes[0]); }
public void Adding_A_Source_Text_Without_Encoding_Fails_Generation() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); var generator = new CallbackGenerator((ic) => { }, (sgc) => { sgc.AddSource("a", SourceText.From("")); }); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out _, out var outputDiagnostics); Assert.Single(outputDiagnostics); outputDiagnostics.Verify( Diagnostic("CS" + (int)ErrorCode.WRN_GeneratorFailedDuringGeneration).WithArguments("CallbackGenerator", "ArgumentException", "The provided SourceText must have an explicit encoding set. (Parameter 'source')").WithLocation(1, 1) ); }
public void Generator_Is_Intialized_Before_Running() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); int initCount = 0, executeCount = 0; var generator = new CallbackGenerator((ic) => initCount++, (sgc) => executeCount++); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var diagnostics); Assert.Equal(1, initCount); Assert.Equal(1, executeCount); }
public void Syntax_Receiver_Is_Not_Created_If_Exception_During_Initialize() { var source = @" class C { int Property { get; set; } void Function() { var x = 5; x += 4; } } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); TestSyntaxReceiver?receiver = null; var exception = new Exception("test exception"); var testGenerator = new CallbackGenerator( onInit: (i) => { i.RegisterForSyntaxNotifications(() => receiver = new TestSyntaxReceiver()); throw exception; }, onExecute: (e) => { Assert.True(false); } ); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver = driver.RunFullGeneration(compilation, out var outputCompilation, out var outputDiagnostics); var results = driver.GetRunResult(); Assert.Null(receiver); outputDiagnostics.Verify( Diagnostic("CS" + (int)ErrorCode.WRN_GeneratorFailedDuringInitialization).WithArguments("CallbackGenerator", "Exception", "test exception").WithLocation(1, 1) ); }
public void Error_During_Generation_With_Dependent_Source() { var source = @" #pragma warning disable CS0649 class C { public D d; } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics( // (5,12): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?) // public D d; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("D").WithLocation(5, 12) ); Assert.Single(compilation.SyntaxTrees); var exception = new InvalidOperationException("generate error"); var generator = new CallbackGenerator((ic) => { }, (sgc) => throw exception, source: "public class D { }"); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(generator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var outputCompilation, out var generatorDiagnostics); outputCompilation.VerifyDiagnostics( // (5,12): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?) // public D d; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("D").WithLocation(5, 12) ); generatorDiagnostics.Verify( // warning CS8785: Generator 'CallbackGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Diagnostic(ErrorCode.WRN_GeneratorFailedDuringGeneration).WithArguments("CallbackGenerator").WithLocation(1, 1) ); }
private static Compilation Compile(string source) { var opt = new CSharpParseOptions(languageVersion: LanguageVersion.Preview, kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse); var copt = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var dotnetCoreDirectory = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); var compilation = CSharpCompilation.Create("test", syntaxTrees: new[] { SyntaxFactory.ParseSyntaxTree(source, opt) }, references: new[] { AssemblyMetadata.CreateFromFile(typeof(object).Assembly.Location).GetReference(), MetadataReference.CreateFromFile(Path.Combine(dotnetCoreDirectory, "netstandard.dll")), MetadataReference.CreateFromFile(Path.Combine(dotnetCoreDirectory, "System.Runtime.dll")), }, options: copt); // apply the source generator var driver = new CSharpGeneratorDriver(opt, ImmutableArray.Create <ISourceGenerator>(new MemberAccessGenerator.MemberAccessGenerator()), null, ImmutableArray <AdditionalText> .Empty); driver.RunFullGeneration(compilation, out var resultCompilation, out _); return(resultCompilation); }
public void Cancellation_During_Execution_Doesnt_Report_As_Generator_Error() { var source = @" class C { } "; var parseOptions = TestOptions.Regular; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); CancellationTokenSource cts = new CancellationTokenSource(); var testGenerator = new CallbackGenerator( onInit: (i) => { }, onExecute: (e) => { cts.Cancel(); } ); // test generator cancels the token. Check that the call to this generator doesn't make it look like it errored. var testGenerator2 = new CallbackGenerator2( onInit: (i) => { }, onExecute: (e) => { e.AddSource("a", SourceText.From("public class E {}", Encoding.UTF8)); } ); GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator, testGenerator2), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty); var oldDriver = driver; Assert.Throws <OperationCanceledException>(() => driver = driver.RunFullGeneration(compilation, out var outputCompilation, out var outputDiagnostics, cts.Token) ); Assert.Same(oldDriver, driver); }