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); }
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(); } }