예제 #1
0
        private string GetGeneratedOutput(string source)
        {
            var syntaxTree = CSharpSyntaxTree.ParseText(source);

            var references = new List <MetadataReference>();

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var assembly in assemblies)
            {
                if (!assembly.IsDynamic)
                {
                    references.Add(MetadataReference.CreateFromFile(assembly.Location));
                }
            }

            var compilation = CSharpCompilation.Create("foo", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            // TODO: Uncomment this line if you want to fail tests when the injected program isn't valid _before_ running generators
            // var compileDiagnostics = compilation.GetDiagnostics();
            // Assert.False(compileDiagnostics.Any(d => d.Severity == DiagnosticSeverity.Error), "Failed: " + compileDiagnostics.FirstOrDefault()?.GetMessage());

            ISourceGenerator generator = new Generator();

            var driver = CSharpGeneratorDriver.Create(generator);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generateDiagnostics);
            Assert.False(generateDiagnostics.Any(d => d.Severity == DiagnosticSeverity.Error), "Failed: " + generateDiagnostics.FirstOrDefault()?.GetMessage());

            string output = outputCompilation.SyntaxTrees.Last().ToString();

            _output.WriteLine(output);

            return(output);
        }
예제 #2
0
        public void Execute_ShouldHandleInvalidSyntax()
        {
            Compilation compilation = CreateCompilation
                                      (
                @"
                using System.Collections;

                using Solti.Utils.Proxy;
                using Solti.Utils.Proxy.Attributes;
                using Solti.Utils.Proxy.Generators;

                [assembly: EmbedGeneratedType(typeof(DuckGenerator<IEnumerable,>))]
                ",
                new[] { typeof(EmbedGeneratedTypeAttribute).Assembly.Location },
                suppressErrors: true
                                      );

            Assert.That(compilation.SyntaxTrees.Count(), Is.EqualTo(1));

            GeneratorDriver driver = CSharpGeneratorDriver.Create(new ProxyEmbedder());

            driver.RunGeneratorsAndUpdateCompilation(compilation, out compilation, out ImmutableArray <Diagnostic> diags);

            Assert.That(diags, Is.Empty);
            Assert.That(compilation.SyntaxTrees.Count(), Is.EqualTo(1));
        }
예제 #3
0
        public void Execute_ShouldWarnOnUnsupportedLanguageVersion()
        {
            Compilation compilation = CreateCompilation
                                      (
                @"
                using System.Collections;

                using Solti.Utils.Proxy;
                using Solti.Utils.Proxy.Attributes;
                using Solti.Utils.Proxy.Generators;

                [assembly: EmbedGeneratedType(typeof(DuckGenerator<IEnumerable, IEnumerable>))]
                ",
                Runtime
                .Assemblies
                .Select(asm => asm.Location)
                .Append(typeof(EmbedGeneratedTypeAttribute).Assembly.Location)
                .Distinct(),
                Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp6
                                      );

            GeneratorDriver driver = CSharpGeneratorDriver.Create
                                     (
                new ISourceGenerator[] { new ProxyEmbedder() },
                parseOptions: new CSharpParseOptions(Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp6)
                                     );

            driver.RunGeneratorsAndUpdateCompilation(compilation, out compilation, out ImmutableArray <Diagnostic> diags);

            Assert.That(diags.Any(diag => diag.Id == "PGE00" && diag.Severity == DiagnosticSeverity.Warning && diag.GetMessage() == SGResources.LNG_NOT_SUPPORTED));
            Assert.That(diags.Length, Is.EqualTo(1));
        }
        public void DoNotGenerateGetServicesForNamedServicesWhenNotNeeded()
        {
            // Given
            var input = CompilationBuilder.CreateAssemblyWithCode(
                @"namespace Demo.Domain
                  {
                      public interface IFoo
                      { }
                  }",
                @"namespace Demo.Domain
                  {
                      using CustomCode.CompileTimeInject.Annotations;

                      [Export]
                      public sealed class Foo : IFoo
                      { }
                  }");
            var sourceGenerator = new IocContainerGenerator();
            var runtime         = CSharpGeneratorDriver.Create(sourceGenerator);

            // When
            runtime.RunGeneratorsAndUpdateCompilation(
                compilation: input,
                outputCompilation: out var output,
                diagnostics: out var diagnostics);

            // Then
            Assert.False(diagnostics.HasErrors());
            Assert.False(output.ContainsTypeWithMethodSignature(
                             "IocContainer",
                             "public T? GetService<T>(string serviceId) where T : class"));
        }
예제 #5
0
        public void GenerateInterfaceStubsSmokeTest()
        {
            var fixture = new InterfaceStubGenerator();

            var driver = CSharpGeneratorDriver.Create(fixture);


            var inputCompilation = CreateCompilation(
                IntegrationTestHelper.GetPath("RestService.cs"),
                IntegrationTestHelper.GetPath("GitHubApi.cs"),
                IntegrationTestHelper.GetPath("InheritedInterfacesApi.cs"),
                IntegrationTestHelper.GetPath("InheritedGenericInterfacesApi.cs"));

            var diags = inputCompilation.GetDiagnostics();

            // Make sure we don't have any errors
            Assert.Empty(diags.Where(d => d.Severity == DiagnosticSeverity.Error));

            var rundriver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompiliation, out var diagnostics);

            var runResult = rundriver.GetRunResult();

            var generated = runResult.Results[0];

            var text = generated.GeneratedSources.First().SourceText.ToString();

            Assert.Contains("IGitHubApi", text);
            Assert.Contains("IAmInterfaceC", text);
        }
예제 #6
0
        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 = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics);

            outputCompilation.VerifyDiagnostics();
            generatorDiagnostics.Verify(
                Diagnostic("TG001").WithLocation(1, 1)
                );
        }
예제 #7
0
        private static (ImmutableArray <Diagnostic> Diagnostics, string Output) GetGeneratedOutput(string source)
        {
            var syntaxTree = CSharpSyntaxTree.ParseText(source);

            var references = new List <MetadataReference>();

            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (!assembly.IsDynamic)
                {
                    references.Add(MetadataReference.CreateFromFile(assembly.Location));
                }
            }

            var compilation = CSharpCompilation.Create("foo", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            var diagnostics = compilation.GetDiagnostics();

            if (diagnostics.Any())
            {
                return(diagnostics, string.Empty);
            }

            var generator = new EventGenerator();

            var driver = CSharpGeneratorDriver.Create(generator);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out diagnostics);

            return(diagnostics, outputCompilation.SyntaxTrees.Last().ToString());
        }
예제 #8
0
        public void Syntax_Receiver_Can_Be_Registered_Only_Once()
        {
            var         source       = @"
class C { }
";
            var         parseOptions = TestOptions.Regular;
            Compilation compilation  = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions);

            compilation.VerifyDiagnostics();

            Assert.Single(compilation.SyntaxTrees);

            var testGenerator = new CallbackGenerator(
                onInit: initialize,
                onExecute: (e) => { }
                );

            GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out _, out _);

            void initialize(GeneratorInitializationContext initContext)
            {
                initContext.RegisterForSyntaxNotifications(() => new TestSyntaxReceiver());
                Assert.Throws <InvalidOperationException>(() =>
                {
                    initContext.RegisterForSyntaxNotifications(() => new TestSyntaxReceiver());
                });
            }
        }
예제 #9
0
    protected Task Verify(string source, Action <Compilation, ImmutableArray <Diagnostic> >?verifyCompilation)
    {
        var syntaxTree = CSharpSyntaxTree.ParseText(source);

        var assemblyDirectory = Path.GetDirectoryName(typeof(object).Assembly.Location) !;
        var references        = new[]
        {
            typeof(object),
            typeof(Enumerable)
        }.Select(t => MetadataReference.CreateFromFile(t.Assembly.Location))
        .Concat(new []
        {
            MetadataReference.CreateFromFile(Path.Combine(assemblyDirectory, "System.Runtime.dll")),
            MetadataReference.CreateFromFile(Path.Combine(assemblyDirectory, "System.Collections.dll")),
        });

        var compilation = CSharpCompilation.Create(
            assemblyName: "Tests",
            syntaxTrees: new[] { syntaxTree },
            references: references,
            options: new(OutputKind.DynamicallyLinkedLibrary));

        GeneratorDriver driver = CSharpGeneratorDriver.Create(new ResultTypeGenerator(), new UnionTypeGenerator());

        driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var updatedCompilation, out var diagnostics);

        verifyCompilation?.Invoke(updatedCompilation, diagnostics);

        return(Verify(driver)
               .UseDirectory("Snapshots"));
    }
예제 #10
0
        public void Syntax_Receiver_Is_Present_When_Registered()
        {
            var         source       = @"
class C { }
";
            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 = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out _, out _);

            Assert.NotNull(receiver);
            Assert.IsType <TestSyntaxReceiver>(receiver);
        }
예제 #11
0
        public void Syntax_Receiver_Is_Null_WhenNot_Registered()
        {
            var         source       = @"
class C { }
";
            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) => { },
                onExecute: (e) => receiver = e.SyntaxReceiver
                );

            GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out _);

            Assert.Null(receiver);
        }
예제 #12
0
        private static (ImmutableArray <Diagnostic>, string) GetGeneratedOutput(string source)
        {
            var syntaxTree = CSharpSyntaxTree.ParseText(source);

            var references = new List <MetadataReference>();

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var assembly in assemblies)
            {
                if (!assembly.IsDynamic)
                {
                    references.Add(MetadataReference.CreateFromFile(assembly.Location));
                }
            }

            var compilation = CSharpCompilation.Create("foo", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            // TODO: Uncomment these lines if you want to return immediately if the injected program isn't valid _before_ running generators
            //
            // ImmutableArray<Diagnostic> compilationDiagnostics = compilation.GetDiagnostics();
            //
            // if (diagnostics.Any())
            // {
            //     return (diagnostics, "");
            // }

            ISourceGenerator generator = new Generator();

            var driver = CSharpGeneratorDriver.Create(generator);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generateDiagnostics);

            return(generateDiagnostics, outputCompilation.SyntaxTrees.Last().ToString());
        }
        /// <summary>
        /// Verifies the output of a source generator.
        /// </summary>
        /// <typeparam name="TGenerator">The generator type to use.</typeparam>
        /// <param name="source">The input source to process.</param>
        /// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
        private void VerifyGeneratedDiagnostics <TGenerator>(string source, params string[] diagnosticsIds)
            where TGenerator : class, ISourceGenerator, new()
        {
            Type validationAttributeType = typeof(ValidationAttribute);

            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source);

            IEnumerable <MetadataReference> references =
                from assembly in AppDomain.CurrentDomain.GetAssemblies()
                where !assembly.IsDynamic
                let reference = MetadataReference.CreateFromFile(assembly.Location)
                                select reference;

            CSharpCompilation compilation = CSharpCompilation.Create("original", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            ISourceGenerator generator = new TGenerator();

            CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray <Diagnostic> diagnostics);

            HashSet <string> resultingIds = diagnostics.Select(diagnostic => diagnostic.Id).ToHashSet();

            Assert.IsTrue(resultingIds.SetEquals(diagnosticsIds));

            GC.KeepAlive(validationAttributeType);
        }
        private GeneratorDriverRunResult RunGenerator(Compilation compilation)
        {
            _testOutputHelper.WriteLine("Running generator and updating compilation...");

            var subject = new ScenarioTestGenerator();
            var driver  = CSharpGeneratorDriver
                          .Create(subject)
                          .RunGenerators(compilation);

            var result = driver.GetRunResult();

            if (result.Diagnostics.IsEmpty)
            {
                _testOutputHelper.WriteLine("Run did not produce diagnostics");
            }
            else
            {
                _testOutputHelper.WriteLine($"Diagnostics produced:");

                foreach (var diagnostic in result.Diagnostics)
                {
                    _testOutputHelper.WriteLine($" > " + diagnostic.ToString());
                }
            }

            foreach (var newSyntaxTree in result.GeneratedTrees)
            {
                _testOutputHelper.WriteLine($"Produced syntax tree with path produced: {newSyntaxTree.FilePath}");
                _testOutputHelper.WriteLine(newSyntaxTree.GetText().ToString());
            }

            return(driver.GetRunResult());
        }
예제 #15
0
        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 = CSharpGeneratorDriver.Create(new[] { generator, generator2 }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(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)
                );
        }
예제 #16
0
        public void Single_File_Is_Added_OnlyOnce_For_Multiple_Calls()
        {
            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 = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation1, out _);
            driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation2, out _);
            driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation3, out _);

            Assert.Equal(2, outputCompilation1.SyntaxTrees.Count());
            Assert.Equal(2, outputCompilation2.SyntaxTrees.Count());
            Assert.Equal(2, outputCompilation3.SyntaxTrees.Count());

            Assert.NotEqual(compilation, outputCompilation1);
            Assert.NotEqual(compilation, outputCompilation2);
            Assert.NotEqual(compilation, outputCompilation3);
        }
예제 #17
0
        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 = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics);

            outputCompilation.VerifyDiagnostics();

            // Since translated description strings can have punctuation that differs based on locale, simply ensure the
            // exception message is contains in the diagnostic description.
            Assert.Contains(exception.ToString(), generatorDiagnostics.Single().Descriptor.Description.ToString());
        }
예제 #18
0
        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 = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics);

            outputCompilation.VerifyDiagnostics();
            generatorDiagnostics.Verify();
        }
예제 #19
0
        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 = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics);
            outputCompilation.VerifyDiagnostics();
            generatorDiagnostics.Verify();
            Assert.Equal(2, outputCompilation.SyntaxTrees.Count());
        }
예제 #20
0
        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 = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            // run an initial generation pass
            driver = driver.RunGeneratorsAndUpdateCompilation(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);
        }
예제 #21
0
        public static async Task Main(string[] args)
        {
            string sln    = @"G:\github\FlorianGrimm\Latrans\Brimborium.Latrans.sln";
            string csproj = @"G:\github\FlorianGrimm\Latrans\src\DemoWebApp.Logic\DemoWebApp.Logic.csproj";

            csproj = System.IO.Path.GetFullPath(csproj);
            Console.WriteLine($"SourceGen csproj:{csproj};");
            MSBuildLocatorHelper.Init();

            var workspace = MSBuildLocatorHelper.CreateWorkspace(null);

            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();;
            var cancellationToken = cancellationTokenSource.Token;

            cancellationToken.ThrowIfCancellationRequested();
            System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
                cancellationTokenSource.Cancel();
            };
            var solution = await workspace.OpenSolutionAsync(sln, null, cancellationToken);

            var project = solution.Projects.Where(prj => string.Equals(prj.FilePath, csproj, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

            if (project is null)
            {
                System.Console.Error.WriteLine($"csproj: {csproj} not found.");
                return;
            }
            else
            {
                //var project = await workspace.OpenProjectAsync(csproj, null, cancellationToken);
                // project.AnalyzerReferences
                // project.ProjectReferences
                //foreach (var projectReference in project.ProjectReferences) {
                //    var projectId = projectReference.ProjectId;
                //}
                var inputCompilation = await project.GetCompilationAsync(cancellationToken);

                if (inputCompilation is null)
                {
                    //
                }
                else
                {
                    var             generator = new ConfigureHandlersSourceGenerator();
                    GeneratorDriver driver    = CSharpGeneratorDriver.Create(generator);
                    driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
                    var lstDiagnostics = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToList();
                    if (lstDiagnostics.Count > 0)
                    {
                        foreach (var diagnostic in lstDiagnostics)
                        {
                            System.Console.Error.WriteLine(diagnostic.GetMessage());
                        }
                    }
                    else
                    {
                    }
                }
            }
        }
예제 #22
0
        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 = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(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);
        }
예제 #23
0
        /// <summary>
        /// Runs a Roslyn generator over a set of source files.
        /// </summary>
        public static async Task <(IReadOnlyList <Diagnostic>, ImmutableArray <GeneratedSourceResult>)> RunGenerator(
            ISourceGenerator generator,
            IEnumerable <Assembly>?references,
            IEnumerable <string> sources,
            AnalyzerConfigOptionsProvider?optionsProvider = null,
            bool includeBaseReferences          = true,
            CancellationToken cancellationToken = default)
        {
            var proj = CreateTestProject(references, includeBaseReferences);

            var count = 0;

            foreach (var s in sources)
            {
                proj = proj.WithDocument($"src-{count++}.cs", s);
            }

            proj.CommitChanges();
            var comp = await proj !.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false);

            var cgd = CSharpGeneratorDriver.Create(new[] { generator }, optionsProvider: optionsProvider);
            var gd  = cgd.RunGenerators(comp !, cancellationToken);

            var r = gd.GetRunResult();

            return(Sort(r.Results[0].Diagnostics), r.Results[0].GeneratedSources);
        }
예제 #24
0
        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 = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            // run initial generation pass
            driver = driver.RunGeneratorsAndUpdateCompilation(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());
        }
예제 #25
0
        public static void RunGenerator(SourceText sourceText, ISourceGenerator generator)
        {
            var compilation = CSharpCompilation
                              .Create("MyTestAssembly")
                              .WithOptions(new(OutputKind.DynamicallyLinkedLibrary))
                              .WithReferences(
                MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(DependencyObject).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(FrameworkPropertyMetadataOptions).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(RoutedEvent).Assembly.Location))
                              .AddSyntaxTrees(CSharpSyntaxTree.ParseText(sourceText));

            var rr = CSharpGeneratorDriver
                     .Create(generator)
                     .RunGenerators(compilation)
                     .GetRunResult();

            foreach (var result in rr.Results)
            {
                foreach (var generatedSourceResult in result.GeneratedSources)
                {
                    Console.WriteLine(generatedSourceResult.SyntaxTree.ToString());
                }
            }
        }
예제 #26
0
        public void Edits_Are_Applied_During_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 = CSharpGeneratorDriver.Create(parseOptions: parseOptions,
                                                                  generators: ImmutableArray.Create <ISourceGenerator>(testGenerator),
                                                                  optionsProvider: CompilerAnalyzerConfigOptionsProvider.Empty,
                                                                  additionalTexts: ImmutableArray.Create <AdditionalText>(new InMemoryAdditionalText("a\\file1.cs", "")));

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out _);
            Assert.Equal(2, outputCompilation.SyntaxTrees.Count());

            // add multiple edits
            driver = driver.WithPendingEdits(ImmutableArray.Create <PendingEdit>(new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file2.cs", "")),
                                                                                 new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file3.cs", "")),
                                                                                 new AdditionalFileAddedEdit(new InMemoryAdditionalText("a\\file4.cs", ""))));

            // but just do a full generation (don't try apply)
            driver.RunGeneratorsAndUpdateCompilation(compilation, out outputCompilation, out _);
            Assert.Equal(5, outputCompilation.SyntaxTrees.Count());
        }
예제 #27
0
        public void Execute_ShouldReportDiagnosticOnError()
        {
            Compilation compilation = CreateCompilation
                                      (
                @"
                using System.Collections;

                using Solti.Utils.Proxy;
                using Solti.Utils.Proxy.Attributes;
                using Solti.Utils.Proxy.Generators;

                [assembly: EmbedGeneratedType(typeof(DuckGenerator<IEnumerable, object>))]
                ",
                new[] { typeof(EmbedGeneratedTypeAttribute).Assembly.Location },
                suppressErrors: true
                                      );

            Assert.That(compilation.SyntaxTrees.Count(), Is.EqualTo(1));

            GeneratorDriver driver = CSharpGeneratorDriver.Create(new ProxyEmbedder());

            driver.RunGeneratorsAndUpdateCompilation(compilation, out compilation, out ImmutableArray <Diagnostic> diags);

            Assert.That(diags.Any(diag => diag.Id.StartsWith("PGE") && diag.Severity == DiagnosticSeverity.Warning && diag.GetMessage().Contains(string.Format(Resources.MISSING_IMPLEMENTATION, nameof(IEnumerable.GetEnumerator)))));
            Assert.That(diags.Length, Is.EqualTo(1));
            Assert.That(compilation.SyntaxTrees.Count(), Is.EqualTo(1));
        }
예제 #28
0
        public void Error_During_Initialization_Is_Reported()
        {
            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) => { });

            GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics);

            outputCompilation.VerifyDiagnostics();
            generatorDiagnostics.Verify(
                // warning CS8784: Generator 'CallbackGenerator' failed to initialize. It will not contribute to the output and compilation errors may occur as a result. Exception was 'InvalidOperationException' with message 'init error'
                Diagnostic("CS" + (int)ErrorCode.WRN_GeneratorFailedDuringInitialization).WithArguments("CallbackGenerator", "InvalidOperationException", "init error").WithLocation(1, 1)
                );
        }
예제 #29
0
        public static async Task <SyntaxTree> GenerateAsync <T>(string source) where T : ISourceGenerator, new()
        {
            var document = CreateProject(source).Documents.Single();
            var tree     = await document.GetSyntaxTreeAsync();

            if (tree is null)
            {
                throw new InvalidOperationException("Could not get the syntax tree of the sources");
            }

            var compilation = (CSharpCompilation)(await document.Project.GetCompilationAsync()) !;

            if (compilation is null)
            {
                throw new InvalidOperationException("Could not compile the sources");
            }

            var diagnostics = compilation.GetDiagnostics();
//            Assert.Empty(diagnostics.Where(x => x.Severity >= DiagnosticSeverity.Warning));

            ISourceGenerator generator = new T();

            var driver = CSharpGeneratorDriver.Create(
                ImmutableArray.Create(generator),
                ImmutableArray <AdditionalText> .Empty,
                compilation.SyntaxTrees[0].Options as CSharpParseOptions
                );

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out diagnostics);
            Assert.Empty(diagnostics.Where(x => x.Severity >= DiagnosticSeverity.Warning));

            // the syntax tree added by the generator will be the last one in the compilation
            return(outputCompilation.SyntaxTrees.Last(z => !z.FilePath.Contains("AssemblyRegistrationOptions") && !z.FilePath.Contains("GeneratedAssemblyJsonRpcHandlers")));
        }
        public void GenerateDefaultServiceCache()
        {
            // Given
            var input = CompilationBuilder.CreateAssemblyWithCode(
                @"namespace Demo.Domain
                  {
                      public interface IFoo
                      { }
                  }",
                @"namespace Demo.Domain
                  {
                      using CustomCode.CompileTimeInject.Annotations;

                      [Export]
                      public sealed class Foo : IFoo
                      { }
                  }");
            var sourceGenerator = new ServiceCacheGenerator();
            var testEnvironment = CSharpGeneratorDriver.Create(sourceGenerator);

            // When
            testEnvironment.RunGeneratorsAndUpdateCompilation(
                compilation: input,
                outputCompilation: out var output,
                diagnostics: out var diagnostics);

            // Then
            Assert.False(diagnostics.HasErrors());
            Assert.True(output.ContainsClass("ServiceCache"));
            Assert.False(output.ContainsTypeWithMethodSignature(
                             "ServiceCache",
                             "public object GetOrAdd(Type key, string serviceId, Func<string, object> valueFactory)"));
        }