public async Task AddingFileWithNewLibraryImport_DoesNotRegenerateOriginalMethod()
        {
            string source = CodeSnippets.BasicParametersAndModifiers <int>();

            Compilation comp1 = await TestUtils.CreateCompilation(source);

            Microsoft.Interop.LibraryImportGenerator generator = new();
            GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions);

            driver = driver.RunGenerators(comp1);

            Compilation comp2 = comp1.AddSyntaxTrees(CSharpSyntaxTree.ParseText(CodeSnippets.BasicParametersAndModifiers <bool>(), new CSharpParseOptions(LanguageVersion.Preview)));

            GeneratorDriver    driver2   = driver.RunGenerators(comp2);
            GeneratorRunResult runResult = driver2.GetRunResult().Results[0];

            Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation],
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason));
            },
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.New, output.Reason));
            });
        }
Exemple #2
0
        public async Task ReplacingFileWithNewLibraryImport_DoesNotRegenerateStubsInOtherFiles()
        {
            Compilation comp1 = await TestUtils.CreateCompilation(new string[] { CodeSnippets.BasicParametersAndModifiers <int>(), CodeSnippets.MarshalAsParametersAndModifiers <bool>(UnmanagedType.I1) });

            Microsoft.Interop.LibraryImportGenerator generator = new();
            GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions);

            driver = driver.RunGenerators(comp1);

            Compilation        comp2     = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), CSharpSyntaxTree.ParseText(CodeSnippets.BasicParametersAndModifiers <ulong>(), new CSharpParseOptions(LanguageVersion.Preview)));
            GeneratorDriver    driver2   = driver.RunGenerators(comp2);
            GeneratorRunResult runResult = driver2.GetRunResult().Results[0];

            Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation],
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason));
            },
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason));
            });
        }
        public async Task AppendingUnrelatedSource_DoesNotRegenerateSource()
        {
            string source = $"namespace NS{{{CodeSnippets.BasicParametersAndModifiers<int>()}}}";

            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview));

            Compilation comp1 = await TestUtils.CreateCompilation(new[] { syntaxTree });

            Microsoft.Interop.LibraryImportGenerator generator = new();
            GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions);

            driver = driver.RunGenerators(comp1);

            SyntaxTree newTree = syntaxTree.WithRootAndOptions(syntaxTree.GetCompilationUnitRoot().AddMembers(SyntaxFactory.ParseMemberDeclaration("struct Foo {}") !), syntaxTree.Options);

            Compilation        comp2     = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), newTree);
            GeneratorDriver    driver2   = driver.RunGenerators(comp2);
            GeneratorRunResult runResult = driver2.GetRunResult().Results[0];

            Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation],
                              step =>
            {
                // The input contains symbols and Compilation objects, so it will always be different.
                // However, we validate that the calculated stub information is identical.
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason));
            });
        }
Exemple #4
0
        public void AddJsonMergePatch_AddsExtensionMethod()
        {
            // Create the 'input' compilation that the generator will act on
            Compilation     inputCompilation = CreateCompilation(@"
namespace TestCode1
{
    public class Dto { public int Property { get; set; }  }
    public class Program
    {
        public void SomeMethod(LaDeak.JsonMergePatch.Abstractions.Patch<Dto> data)
        {
        }
    }
}
");
            var             commonGenerator  = new JsonMergePatchSourceGenerator();
            var             sut    = new AspNetJsonMergePatchSourceGenerator();
            GeneratorDriver driver = CSharpGeneratorDriver.Create(commonGenerator, sut);

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

            Assert.True(diagnostics.IsEmpty);

            GeneratorDriverRunResult runResult       = driver.GetRunResult();
            GeneratorRunResult       testedGenerator = runResult.Results[1];

            Assert.Single(testedGenerator.GeneratedSources);
            Assert.Empty(testedGenerator.Diagnostics);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="AttributeTargetGeneratorTestResult"/> struct.
        /// </summary>
        /// <param name="generatorDriver">A <see cref="CSharpGeneratorDriver"/> that was used to perform the test.</param>
        /// <param name="inputCompilation">A <see cref="CSharpCompilation"/> that represent an input for the tested <see cref="ISourceGenerator"/>.</param>
        /// <param name="outputCompilation">A <see cref="CSharpCompilation"/> that was created by the tested <see cref="ISourceGenerator"/>.</param>
        public AttributeTargetGeneratorTestResult(GeneratorDriver generatorDriver, CSharpCompilation inputCompilation, CSharpCompilation outputCompilation)
        {
            InputCompilation  = inputCompilation;
            OutputCompilation = outputCompilation;
            _runResult        = generatorDriver.GetRunResult().Results[0];

            if (_runResult.Exception is null && _runResult.GeneratedSources.Length > 1)
            {
                Attribute = _runResult.GeneratedSources[0];
                Source    = _runResult.GeneratedSources[1];

                IsGenerated = Attribute.SyntaxTree is CSharpSyntaxTree && Source.SyntaxTree is CSharpSyntaxTree;
            }
Exemple #6
0
        public void Verify_generator_works()
        {
            // Create the 'input' compilation that the generator will act on
            Compilation inputCompilation = CreateCompilation(@"
[assembly: NServiceBusEndpointName(""test"")]
namespace MyCode
{
    public class Program
    {
        public static void Main(string[] args)
        {
        }
    }
}
");

            // directly create an instance of the generator
            // (Note: in the compiler this is loaded from an assembly, and created via reflection at runtime)
            var generator = new CodeGenLibrary.FunctionEndpointTriggerGenerator();

            // Create the driver that will control the generation, passing in our generator
            GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

            // Run the generation pass
            // (Note: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls)
            driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);

            // We can now assert things about the resulting compilation:
            Debug.Assert(diagnostics.IsEmpty);                        // there were no diagnostics created by the generators
            Debug.Assert(outputCompilation.SyntaxTrees.Count() == 3); // we have 3 syntax trees, the original 'user' provided one, attribute, and a trigger class
            //Debug.Assert(outputCompilation.GetDiagnostics().IsEmpty); // verify the compilation with the added source has no diagnostics

            // Or we can look at the results directly:
            GeneratorDriverRunResult runResult = driver.GetRunResult();

            // The runResult contains the combined results of all generators passed to the driver
            Debug.Assert(runResult.GeneratedTrees.Length == 2);
            Debug.Assert(runResult.Diagnostics.IsEmpty);

            // Or you can access the individual results on a by-generator basis
            GeneratorRunResult generatorResult = runResult.Results[0];

            Debug.Assert(generatorResult.Generator == generator);
            Debug.Assert(generatorResult.Diagnostics.IsEmpty);
            Debug.Assert(generatorResult.GeneratedSources.Length == 2);
            Debug.Assert(generatorResult.Exception is null);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="SingletonGeneratorTestResult"/> struct.
        /// </summary>
        /// <param name="generatorDriver">A <see cref="CSharpGeneratorDriver"/> that was used to perform the test.</param>
        /// <param name="inputCompilation">A <see cref="CSharpCompilation"/> that represent an input for the tested <see cref="ISourceGenerator"/>.</param>
        /// <param name="outputCompilation">A <see cref="CSharpCompilation"/> that was created by the tested <see cref="ISourceGenerator"/>.</param>
        /// <param name="sourceIndex">Index of the target <see cref="CSharpSyntaxTree"/> in the generator's output.</param>
        public SingletonGeneratorTestResult(CSharpGeneratorDriver generatorDriver, CSharpCompilation inputCompilation, CSharpCompilation outputCompilation, int sourceIndex)
        {
            InputCompilation  = inputCompilation;
            OutputCompilation = outputCompilation;
            _runResult        = generatorDriver.GetRunResult().Results[0];
            bool isGenerated = _runResult.Exception is null && _runResult.GeneratedSources.Length > sourceIndex;

            if (isGenerated)
            {
                _sourceResult = _runResult.GeneratedSources[sourceIndex];
                _tree         = _sourceResult.SyntaxTree as CSharpSyntaxTree;
                isGenerated   = _tree is not null;
            }
            else
            {
                _sourceResult = default;
                _tree         = null;
            }

            IsGenerated = isGenerated;
        }
        public async Task ChangingMarshallingStrategy_RegeneratesStub()
        {
            string stubSource = CodeSnippets.BasicParametersAndModifiers("CustomType");

            string customTypeImpl1 = "struct CustomType { System.IntPtr handle; }";

            string customTypeImpl2 = "class CustomType : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { public CustomType():base(true){} protected override bool ReleaseHandle(){return true;} }";


            Compilation comp1 = await TestUtils.CreateCompilation(stubSource);

            SyntaxTree customTypeImpl1Tree = CSharpSyntaxTree.ParseText(customTypeImpl1, new CSharpParseOptions(LanguageVersion.Preview));

            comp1 = comp1.AddSyntaxTrees(customTypeImpl1Tree);

            Microsoft.Interop.LibraryImportGenerator generator = new();
            GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions);

            driver = driver.RunGenerators(comp1);

            Compilation        comp2     = comp1.ReplaceSyntaxTree(customTypeImpl1Tree, CSharpSyntaxTree.ParseText(customTypeImpl2, new CSharpParseOptions(LanguageVersion.Preview)));
            GeneratorDriver    driver2   = driver.RunGenerators(comp2);
            GeneratorRunResult runResult = driver2.GetRunResult().Results[0];

            Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation],
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason));
            });

            Assert.Collection(runResult.TrackedSteps[StepNames.GenerateSingleStub],
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason));
            });
        }
        public async Task ChangingMarshallingAttributes_SameStrategy_DoesNotRegenerate()
        {
            string source = CodeSnippets.BasicParametersAndModifiers <int>();

            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview));

            Compilation comp1 = await TestUtils.CreateCompilation(new[] { syntaxTree });

            Microsoft.Interop.LibraryImportGenerator generator = new();
            GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions);

            driver = driver.RunGenerators(comp1);

            SyntaxTree newTree = syntaxTree.WithRootAndOptions(
                SyntaxFactory.ParseCompilationUnit(
                    CodeSnippets.MarshalAsParametersAndModifiers <int>(System.Runtime.InteropServices.UnmanagedType.I4)),
                syntaxTree.Options);

            Compilation comp2 = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), newTree);

            GeneratorDriver    driver2   = driver.RunGenerators(comp2);
            GeneratorRunResult runResult = driver2.GetRunResult().Results[0];

            Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation],
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason));
            });

            Assert.Collection(runResult.TrackedSteps[StepNames.GenerateSingleStub],
                              step =>
            {
                Assert.Collection(step.Outputs,
                                  output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason));
            });
        }
Exemple #10
0
    public void SimpleGeneratorTest()
    {
        // Input for our generator.
        Compilation inputCompilation = CreateCompilation(@"
namespace WalletWasabi.Fluent.ViewModels
{
	public class TestViewModel2
	{
		[AutoNotify(PropertyName = ""TestName"")] private bool _prop1;
		[AutoNotify(SetterModifier = AccessModifier.None)] private bool _prop2 = false;
		[AutoNotify(SetterModifier = AccessModifier.Public)] private bool _prop3;
		[AutoNotify(SetterModifier = AccessModifier.Protected)] private bool _prop4;
		[AutoNotify(SetterModifier = AccessModifier.Private)] private bool _prop5;
		[AutoNotify(SetterModifier = AccessModifier.Internal)] private bool _prop6;
	}
}
");

        AutoNotifyGenerator generator = new();
        GeneratorDriver     driver    = CSharpGeneratorDriver.Create(generator);

        // Run the generation pass
        driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);

        Assert.True(diagnostics.IsEmpty);
        Assert.Equal(4, outputCompilation.SyntaxTrees.Count());

        GeneratorDriverRunResult runResult = driver.GetRunResult();

        Assert.Equal(3, runResult.GeneratedTrees.Length);
        Assert.True(runResult.Diagnostics.IsEmpty);

        GeneratorRunResult generatorResult = runResult.Results[0];

        Assert.True(generatorResult.Exception is null);
        Assert.Equal(generatorResult.Generator, generator);
        Assert.True(generatorResult.Diagnostics.IsEmpty);
        Assert.Equal(3, generatorResult.GeneratedSources.Length);

        string expectedGeneratedSourceCode = @"
// <auto-generated />
#nullable enable
using ReactiveUI;

namespace WalletWasabi.Fluent.ViewModels
{
    public partial class TestViewModel2 : ReactiveUI.ReactiveObject
    {
        public bool TestName
        {
            get => _prop1;
            set => this.RaiseAndSetIfChanged(ref _prop1, value);
        }
        public bool Prop2
        {
            get => _prop2;
        }
        public bool Prop3
        {
            get => _prop3;
            set => this.RaiseAndSetIfChanged(ref _prop3, value);
        }
        public bool Prop4
        {
            get => _prop4;
            protected set => this.RaiseAndSetIfChanged(ref _prop4, value);
        }
        public bool Prop5
        {
            get => _prop5;
            private set => this.RaiseAndSetIfChanged(ref _prop5, value);
        }
        public bool Prop6
        {
            get => _prop6;
            internal set => this.RaiseAndSetIfChanged(ref _prop6, value);
        }
    }
}".Trim();

        Assert.Equal(expectedGeneratedSourceCode, generatorResult.GeneratedSources[2].SourceText.ToString());
    }
Exemple #11
0
        public void GenerationFormat()
        {
            var         source           = @"using DevExpress.Mvvm.CodeGenerators;

namespace Test {
    [GenerateViewModel(ImplementINotifyPropertyChanging = true, ImplementIDataErrorInfo = true, ImplementISupportServices = true)]
    partial class Example {
        [GenerateProperty]
        [System.ComponentModel.DataAnnotations.Range(0,
                                                     1)]
        int property;
        
        [GenerateCommand]
        public void Method(int arg) { }
    }

    public class Program {
        public static void Main(string[] args) { }
    }
}
";
            Compilation inputCompilation = CSharpCompilation.Create("MyCompilation",
                                                                    new[] { CSharpSyntaxTree.ParseText(source) },
                                                                    new[] {
                MetadataReference.CreateFromFile(typeof(DelegateCommand).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RangeAttribute).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location),
                MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
            },
                                                                    new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
            ViewModelGenerator generator = new ViewModelGenerator();

            GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

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

            GeneratorDriverRunResult runResult       = driver.GetRunResult();
            GeneratorRunResult       generatorResult = runResult.Results[0];

            var generatedCode = generatorResult.GeneratedSources[1].SourceText.ToString();
            var tabs          = 0;

            foreach (var str in generatedCode.Split(new[] { Environment.NewLine }, StringSplitOptions.None))
            {
                if (string.IsNullOrEmpty(str))
                {
                    continue;
                }

                if (str.Contains("}") && !str.Contains("{"))
                {
                    if (str.EndsWith("}"))
                    {
                        tabs--;
                    }
                    else
                    {
                        Assert.Fail();
                    }
                }

                var expectedLeadingWhitespaceCount = tabs * 4;
                var leadingWhitespaceCount         = str.Length - str.TrimStart().Length;
                Assert.AreEqual(expectedLeadingWhitespaceCount, leadingWhitespaceCount);

                if (str.EndsWith("{"))
                {
                    tabs++;
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="MultiOutputGeneratorTestResult"/> struct.
 /// </summary>
 /// <param name="generatorDriver">A <see cref="CSharpGeneratorDriver"/> that was used to perform the test.</param>
 /// <param name="inputCompilation">A <see cref="CSharpCompilation"/> that represent an input for the tested <see cref="ISourceGenerator"/>.</param>
 /// <param name="outputCompilation">A <see cref="CSharpCompilation"/> that was created by the tested <see cref="ISourceGenerator"/>.</param>
 public MultiOutputGeneratorTestResult(GeneratorDriver generatorDriver, CSharpCompilation inputCompilation, CSharpCompilation outputCompilation)
 {
     InputCompilation  = inputCompilation;
     OutputCompilation = outputCompilation;
     _runResult        = generatorDriver.GetRunResult().Results[0];
 }
        public void Test_InterfaceExtensionsGenerator()
        {
            // Create the 'input' compilation that the generator will act on
            Compilation inputCompilation = CreateCompilation(@"
using System;

namespace MyCode {

    [UltimateOrb.CodeAnalysis.SourceGenerators.GeneratExtensions]
    interface IInterfaceA<T> {

        bool Property1 {

            get;
        }

        internal bool Property2 {

            set;
        }

        public bool Property3 {

            get;
            protected set;
        }

        static int Method4() {
            return 123;
        }

        public long Method5() {
            return 123;
        }

        void Method6(ref long arg1, in uint? arg2 , in string? arg3, Guid arg4) {
            return;
        }

        protected void Method7(ref ulong arg1, in uint? arg2, in string? arg3, Guid arg4);

        void Method8(ref nint arg1, in UIntPtr? arg2, in string? arg3, Guid arg4);

    }
}
");

            // directly create an instance of the generator
            // (Note: in the compiler this is loaded from an assembly, and created via reflection at runtime)
            var generator = new InterfaceExtensionsGenerator();

            // Create the driver that will control the generation, passing in our generator
            GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

            // Run the generation pass
            // (Note: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls)
            driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);

            // We can now assert things about the resulting compilation:
            Debug.Assert(diagnostics.IsEmpty);                        // there were no diagnostics created by the generators
            Debug.Assert(outputCompilation.SyntaxTrees.Count() == 2); // we have two syntax trees, the original 'user' provided one, and the one added by the generator
            System.Collections.Immutable.ImmutableArray <Diagnostic> diagnostics1 = outputCompilation.GetDiagnostics();
            Debug.Assert(diagnostics1.IsEmpty);                       // verify the compilation with the added source has no diagnostics

            // Or we can look at the results directly:
            GeneratorDriverRunResult runResult = driver.GetRunResult();

            // The runResult contains the combined results of all generators passed to the driver
            Debug.Assert(runResult.GeneratedTrees.Length == 1);
            Debug.Assert(runResult.Diagnostics.IsEmpty);

            // Or you can access the individual results on a by-generator basis
            GeneratorRunResult generatorResult = runResult.Results[0];

            Debug.Assert(generatorResult.Generator == generator);
            Debug.Assert(generatorResult.Diagnostics.IsEmpty);
            Debug.Assert(generatorResult.GeneratedSources.Length == 1);
            Debug.Assert(generatorResult.Exception is null);
        }