예제 #1
0
        public void TestInterfaceImplementation()
        {
            var target = new ImplementationGenerator(
                MethodInfo.GetCurrentMethod().Name,
                CanReturnThis);

            target.PlanImplementationOf(typeof(ITestRoot));

            Assembly assembly;

            Assert.IsTrue(ResourceContext.Instance.LoadOrBuild(target, out assembly));

            string className = target.PlannedClassNames[0];
            var    inst      = (ITestRoot)Activator.CreateInstance(assembly.GetType(className));

            Assert.AreEqual(0, inst.ValueReturningMethod2(null));

            Assert.AreEqual(0, inst.ValueProperty2);
            inst.ValueProperty2 = 555;
            Assert.AreEqual(0, inst.ValueProperty2);

            Assert.IsNull(inst.ObjectReturningMethod2(null));

            Assert.IsNull(inst.ObjectProperty2);

            Assert.IsNull(inst.ObjectReturningMethod2(null));

            Assert.AreEqual(0, inst.ValueProperty0);

            Assert.AreEqual(0, inst.ValueProperty1);

            Assert.AreSame(inst, inst.AspectMethod1(null));

            Assert.AreEqual(0, inst.AspectMethod1(null).ValueProperty3);
        }
        public (SourceText?source, IReadOnlyList <Diagnostic> diagnostics) CreateImplementation(INamedTypeSymbol namedTypeSymbol)
        {
            // If we've got any symbols errors from just instantiating it, we're going to have a bad time. Give up now.
            if (this.symbolsDiagnosticReporter.HasErrors)
            {
                return(null, Array.Empty <Diagnostic>());
            }

            var diagnosticReporter = new DiagnosticReporter();
            var analyzer           = new RoslynTypeAnalyzer(this.compilation, namedTypeSymbol, this.wellKnownSymbols, this.attributeInstantiator, diagnosticReporter);
            var typeModel          = analyzer.Analyze();
            var generator          = new ImplementationGenerator(typeModel, this.emitter, diagnosticReporter);
            var emittedType        = generator.Generate();

            // If there are symbols diagnostic errors, we have to fail this type.
            // However, we'll then clear the symbols diagnostics, so we can move onto the next type
            // (which might succeed).
            // We'll report the symbols diagnostics in one go at the end. We might well end up with duplicates
            // (WellKnownSymbols will keep reporting the same diagnostics), so use a HashSet.

            this.symbolsDiagnostics.UnionWith(this.symbolsDiagnosticReporter.Diagnostics);
            bool hasSymbolsErrors = this.symbolsDiagnosticReporter.HasErrors;

            this.symbolsDiagnosticReporter.Clear();

            return(hasSymbolsErrors || diagnosticReporter.HasErrors
                ? null
                : emittedType.SourceText, diagnosticReporter.Diagnostics);
        }
        private void GenerateAndAssertSnapshot(
            string patternInterfaceFile,
            string patternImplementationFile,
            string declarationInterfaceFile,
            string targetNameSpace,
            string implName,
            string snapshotName)
        {
            this.LoadWorkSpace(
                patternInterfaceFile,
                patternImplementationFile,
                declarationInterfaceFile,
                out var itfDeclaration,
                out var itfPatternDeclaration,
                out var implPatternDeclaration);

            var locator = new RelativeLocator(string.Empty, targetNameSpace);

            var snapshotGenerator = new SnapshotGenerator();

            var implGenerator = new ImplementationGenerator(
                snapshotGenerator, locator, itfPatternDeclaration, implPatternDeclaration);

            var writerSelector = SetupWriterSelector(itfPatternDeclaration, implPatternDeclaration, itfDeclaration, implName);

            implGenerator.Generate(writerSelector, itfDeclaration, implName);

            string location = SnapshotHelper.GetLocationFromCallingProjectRoot("Generator");

            SnapshotHelper.AssertSnapshot(snapshotGenerator.GetAllGenerated(), snapshotName, location);
        }
        /// <summary>
        /// Process the generator.
        /// </summary>
        /// <param name="projectFile">The project file to work from.</param>
        public void Generate(string projectFile)
        {
            this.logger.LogInformation($"Loading {Path.GetFileName(projectFile)}...");

            var projectFolder = Path.GetDirectoryName(projectFile);

            // First we need to register the project.
            var project = this.workspace.RegisterProject(projectFile);

            // Register the pattern interface.
            var patternInterfaceDeclaration = this.workspace.RegisterFile("./Patterns/Itf/IModelPattern.cs")
                                              .Declarations.Single() as IInterfaceDeclaration;

            // Register the pattern implementation.
            var patternImplementationDeclaration = this.workspace.RegisterFile("./Patterns/Impl/ModelPattern.cs")
                                                   .Declarations.Single() as IGenericDeclaration <SyntaxNode>;

            // Load the project and its project dependencies. (Note that for now we only load the sources.
            // The binary assembly dependencies are not taken into account)
            var resolver = this.workspace.DeepLoad();

            // Get the base interface in order to find all extended interfaces that need to be implemented.
            var modelBaseInterface = resolver.Find("SoloX.GeneratorTools.Core.CSharp.Examples.Core.IModelBase").Single() as IGenericDeclaration <SyntaxNode>;

            // Setup a locator that will tell the location where the generated classes must be written.
            var locator = new RelativeLocator(projectFolder, project.RootNameSpace, suffix: "Impl");

            // Create the Implementation Generator with a file generator, the locator and the pattern interface/class.
            var generator = new ImplementationGenerator(
                new FileGenerator(".generated.cs"),
                locator,
                patternInterfaceDeclaration,
                patternImplementationDeclaration);

            // Loop on all interface extending the base interface.
            foreach (var modelInterface in modelBaseInterface.ExtendedBy.Where(d => d != patternInterfaceDeclaration))
            {
                this.logger.LogInformation(modelInterface.FullName);

                var implName = GeneratorHelper.ComputeClassName(modelInterface.Name);

                // Create the property writer what will use all properties from the model interface to generate
                // and write the corresponding code depending on the given patterns.
                var propertyWriter = new PropertyWriter(
                    patternInterfaceDeclaration.Properties.Single(),
                    modelInterface.Properties);

                // Setup some basic text replacement writer.
                var itfNameWriter  = new StringReplaceWriter(patternInterfaceDeclaration.Name, modelInterface.Name);
                var implNameWriter = new StringReplaceWriter(patternImplementationDeclaration.Name, implName);

                // Create the writer selector.
                var writerSelector = new WriterSelector(propertyWriter, itfNameWriter, implNameWriter);

                // And generate the class implementation.
                generator.Generate(writerSelector, (IInterfaceDeclaration)modelInterface, implName);
            }
        }
        public LanguageDerivedBuilder(Type definitionType)
        {
            this.languageName = new CilGrammarSource(definitionType);

            var dataProvider = new LanguageDataProvider(languageName, false);

            ResourceContext.Instance.LoadOrBuild(dataProvider, out this.data);

            // TODO: Share abstraction impelementation between languages i.e. shared plan
            this.implementationGenerator = new ImplementationGenerator(
                null,
                IsMethodWithNonNullResult);
        }
예제 #6
0
        static void Main(string[] args)
        {
            var context = GetContext(args);

            var apiModels     = new RoslynModelGenerator().Generate(context);
            var generatedCode = new ImplementationGenerator().Generate(context, apiModels);
            var success       = new ProjectMutator().Mutate(context, generatedCode);

            Console.WriteLine(
                $"Generated interfaces for {apiModels.Count} types:{Environment.NewLine}" +
                String.Join(Environment.NewLine, apiModels.Select(x => $" - {x.Api} ({x.Declarations.Count} members)")));

            if (Debugger.IsAttached)
            {
                Console.ReadLine();
            }
        }