public RichGenerationResult Generate(TransformationContext context) { _context = context; var classSyntax = (ClassDeclarationSyntax)context.ProcessingNode; var model = context.SemanticModel; ClassDeclarationSyntax classDeclaration = null; var classSemantic = model.GetDeclaredSymbol(classSyntax); var className = $"{classSemantic.Name}"; try { classDeclaration = GenerateClass(classSemantic, className); classDeclaration = AddPublish(classSyntax, model, classDeclaration, "PublishEvent", "Event"); classDeclaration = AddBuildMethod(classSyntax, model, classDeclaration, "HomeCenter.Model.Messages.Commands.Command", "CreateCommand", "Command"); } catch (Exception e) { Logger.Error(e.ToString(), ""); classDeclaration = ClassDeclaration(className).WithCloseBraceToken(Token(TriviaList(Comment($"//{e}")), SyntaxKind.CloseBraceToken, TriviaList())); } var namespaveDeclaration = AddNamespace(classSyntax, classDeclaration); var result = new RichGenerationResult { Members = List <MemberDeclarationSyntax>().Add(namespaveDeclaration) }; return(result); }
private Task <RichGenerationResult> GenerateAsync(TypeDeclarationSyntax typeDeclaration, TransformationContext context, AttributeData attributeData) { if (!(context.ProcessingNode.Parent is NamespaceDeclarationSyntax namespaceDeclarationSyntax)) { throw new Exception($"Failed to determine namespace for type:'{context.ProcessingNode.Parent}'."); } #if DEBUG var attachDebuggerOnNode = attributeData.GetNamedArgumentValueOrDefault <bool>(nameof(ImplementInterfaceAttribute.AttachDebuggerOnNode)); if (attachDebuggerOnNode) { Debugger.Launch(); } #endif var descriptor = GetImplementationDescriptor(typeDeclaration, context, attributeData); var implementationMemberDeclaration = GetImplementation(descriptor); var @namespace = NamespaceDeclaration(namespaceDeclarationSyntax.Name) .AddMembers(implementationMemberDeclaration); var generatedMembers = new List <MemberDeclarationSyntax> { @namespace }; var result = new RichGenerationResult { Members = new SyntaxList <MemberDeclarationSyntax>(generatedMembers) }; return(Task.FromResult(result)); }
public Task <RichGenerationResult> GenerateRichAsync(TransformationContext context, IProgress <Diagnostic> progress, CancellationToken cancellationToken) { File.WriteAllText("S:\\RICH BITCH.txt", "dsadfsa"); IEnumerable <MemberDeclarationSyntax> CreatePartialType() { var newPartialType = context.ProcessingNode is ClassDeclarationSyntax classDeclaration ? SyntaxFactory.ClassDeclaration(classDeclaration.Identifier.ValueText) : context.ProcessingNode is StructDeclarationSyntax structDeclaration ? SyntaxFactory.StructDeclaration(structDeclaration.Identifier.ValueText) : default(TypeDeclarationSyntax); if (newPartialType is null) { yield break; } yield return(newPartialType ?.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword)) .AddMembers(CreateAsyncStateMachine())); } MemberDeclarationSyntax CreateAsyncStateMachine() { return(SyntaxFactory.ParseMemberDeclaration("public class HelloJopa{}")); } var r = new RichGenerationResult { Members = new SyntaxList <MemberDeclarationSyntax>(CreatePartialType().ToList()), }; return(Task.FromResult(r)); }
/// <summary> /// Create the syntax tree representing the expansion of some member to which this attribute is applied. /// </summary> /// <param name="context">All the inputs necessary to perform the code generation.</param> /// <param name="progress">A way to report diagnostic messages.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns> /// The generated member syntax to be added to the project. /// </returns> /// <exception cref="System.NotImplementedException"></exception> public Task <RichGenerationResult> GenerateRichAsync(TransformationContext context, IProgress <Diagnostic> progress, CancellationToken cancellationToken) { var syntaxFactory = SyntaxFactory.CompilationUnit(); syntaxFactory = AddUsings(syntaxFactory); var applyToInterface = (InterfaceDeclarationSyntax)context.ProcessingNode; var namespaceDeclaration = SyntaxFactory .NamespaceDeclaration(SyntaxFactory.ParseName("CodeGenerator")).NormalizeWhitespace(); ClassDeclarationSyntax classDeclaration = GetClassDeclaration(applyToInterface); var interfaceMembers = applyToInterface.Members; foreach (var member in interfaceMembers) { classDeclaration = AddImplementation(member, classDeclaration); } namespaceDeclaration = namespaceDeclaration.AddMembers(classDeclaration); syntaxFactory = syntaxFactory.AddMembers(namespaceDeclaration); var richGenerationResult = new RichGenerationResult(); richGenerationResult.Members = syntaxFactory.Members; richGenerationResult.Usings = syntaxFactory.Usings; return(Task.FromResult(richGenerationResult)); }
/// <summary> /// Create additions to compilation unit representing the expansion of some node to which this attribute is applied. /// </summary> /// <param name="context">All the inputs necessary to perform the code generation.</param> /// <param name="progress">A way to report diagnostic messages.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns>The generated syntax nodes to be added to the compilation unit added to the project.</returns> public async Task <RichGenerationResult> GenerateRichAsync(TransformationContext context, IProgress <Diagnostic> progress, CancellationToken cancellationToken) { var node = context.ProcessingNode; var result = new RichGenerationResult { Members = context.ProcessingNode.Ancestors().Aggregate(await this.GenerateAsync(context, progress, cancellationToken), WrapInAncestor), Usings = List( new UsingDirectiveSyntax[] { UsingDirective( IdentifierName("System")), UsingDirective( QualifiedName( IdentifierName("System"), IdentifierName("Reflection"))), UsingDirective( QualifiedName( QualifiedName( IdentifierName("System"), IdentifierName("Collections")), IdentifierName("Generic"))), UsingDirective( QualifiedName( QualifiedName( IdentifierName("System"), IdentifierName("Collections")), IdentifierName("ObjectModel"))), UsingDirective( QualifiedName( QualifiedName( IdentifierName("System"), IdentifierName("Diagnostics")), IdentifierName("CodeAnalysis"))), UsingDirective( IdentifierName("RedCow")), UsingDirective( QualifiedName( IdentifierName("RedCow"), IdentifierName("Immutable"))), UsingDirective( QualifiedName( QualifiedName( IdentifierName("RedCow"), IdentifierName("Immutable")), IdentifierName("Collections"))), }), }; return(result); }
public RichGenerationResult Generate(TransformationContext context, INamedTypeSymbol builderContentType, string from, string to) { _context = context; _builderContentType = builderContentType; var classSyntax = (ClassDeclarationSyntax)context.ProcessingNode; var semanticModel = context.SemanticModel; ClassDeclarationSyntax classDeclaration = null; try { _properties = builderContentType.GetMembers().Where(p => p.Kind == SymbolKind.Property && p.DeclaredAccessibility == Accessibility.Public).Cast <IPropertySymbol>(); GenerateNameMap(from, to); var classSemantic = semanticModel.GetDeclaredSymbol(classSyntax); className = $"{classSemantic.Name}"; classDeclaration = GenerateClass(className); classDeclaration = AddMembers(classDeclaration); foreach (var property in _properties) { var newMethod = AddWithMethod(_namesMap[property.Name], property.Type.Name); classDeclaration = classDeclaration.AddMembers(newMethod); } classDeclaration = classDeclaration.AddMembers(AddBuildMethod()); } catch (Exception e) { Logger.Error(e.ToString(), ""); classDeclaration = ClassDeclaration(className).WithCloseBraceToken(Token(TriviaList(Comment($"//{e}")), SyntaxKind.CloseBraceToken, TriviaList())); } var namespaveDeclaration = AddNamespace(classSyntax, classDeclaration); var result = new RichGenerationResult { Members = List <MemberDeclarationSyntax>().Add(namespaveDeclaration) }; return(result); }
public Task <RichGenerationResult> GenerateRichAsync(TransformationContext context, IProgress <Diagnostic> progress, CancellationToken cancellationToken) { var fullSyntaxPath = Path.Combine(context.ProjectDirectory, _syntaxFile); FileStream fs = null; try { fs = File.OpenRead(fullSyntaxPath); } catch (Exception ex) when(ex is DirectoryNotFoundException || ex is FileNotFoundException) { var fnf = Diagnostic.Create("SCG_FileNotFound", "SyntaxCodeGenerator", $"The syntax file at {fullSyntaxPath} was not found.", DiagnosticSeverity.Error, DiagnosticSeverity.Error, true, 0); progress.Report(fnf); throw; } using (fs) { var reader = XmlReader.Create(fs, new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit }); var serializer = new XmlSerializer(typeof(Tree)); Tree tree = (Tree)serializer.Deserialize(reader); cancellationToken.ThrowIfCancellationRequested(); var stringBuilder = new StringBuilder(); var writer = new StringWriter(stringBuilder); SourceWriter.WriteAll(writer, tree); var syntaxTree = CSharpSyntaxTree.ParseText(stringBuilder.ToString(), cancellationToken: cancellationToken); var root = syntaxTree.GetCompilationUnitRoot(); var rgr = new RichGenerationResult { Usings = root.Usings, Members = root.Members }; return(Task.FromResult(rgr)); } }
public RichGenerationResult Generate(TransformationContext context) { _context = context; var classSyntax = (ClassDeclarationSyntax)context.ProcessingNode; var model = context.SemanticModel; ClassDeclarationSyntax classDeclaration = null; var classSemantic = model.GetDeclaredSymbol(classSyntax); var className = $"{classSemantic.Name}Proxy"; try { classDeclaration = GenerateClass(classSemantic, className); classDeclaration = AddReciveMapMethod(classSyntax, model, classDeclaration); classDeclaration = AddConstructor(classDeclaration, classSemantic, className); classDeclaration = AddSubscriptions(classSyntax, model, classDeclaration); } catch (Exception e) { Logger.Error(e.ToString(), ""); classDeclaration = ClassDeclaration(className).WithCloseBraceToken(Token(TriviaList(Comment($"//{e}")), SyntaxKind.CloseBraceToken, TriviaList())); } var namespaveDeclaration = AddNamespace(classSyntax, classDeclaration); var result = new RichGenerationResult { Members = List <MemberDeclarationSyntax>().Add(namespaveDeclaration) }; result.Usings = GenerateUsingStatements(); return(result); }
".Replace("\r\n", "\n").Replace("\n", Environment.NewLine); // normalize regardless of git checkout policy /// <summary> /// Produces a new document in response to any code generation attributes found in the specified document. /// </summary> /// <param name="csCompilation">The compilation to which the document belongs.</param> /// <param name="inputDocument">The document to scan for generator attributes.</param> /// <param name="projectDirectory">The path of the <c>.csproj</c> project file.</param> /// <param name="assemblyLoader">A function that can load an assembly with the given name.</param> /// <param name="progress">Reports warnings and errors in code generation.</param> /// <returns>A task whose result is the generated document.</returns> public static async Task <(SyntaxTree, bool)> TransformAsync( CSharpCompilation csCompilation, GeneratorKnownTypes generatorKnownTypes, SyntaxTree inputDocument, string projectDirectory, Func <AssemblyName, Assembly> assemblyLoader, IProgress <Diagnostic> progress) { Requires.NotNull(csCompilation, nameof(csCompilation)); Requires.NotNull(inputDocument, nameof(inputDocument)); Requires.NotNull(assemblyLoader, nameof(assemblyLoader)); var inputSemanticModel = csCompilation.GetSemanticModel(inputDocument); var inputCompilationUnit = inputDocument.GetCompilationUnitRoot(); var emittedExterns = inputCompilationUnit .Externs .Select(x => x.WithoutTrivia()) .ToImmutableArray(); var emittedUsings = inputCompilationUnit .Usings .Select(x => x.WithoutTrivia()) .ToImmutableArray(); async Task <(CSharpCompilation compilation, SemanticModel semanticModel, SyntaxNode resRootNode, SyntaxNode resRootNodeTracked, bool treeChanged, RichGenerationResult richGenerationResult)> ProcessNodeTransformation( CSharpCompilation compilation, SemanticModel semanticModel, SyntaxNode rootNode, SyntaxNode rootNodeTracked, bool treeChanged, SyntaxNode workNode) { (SyntaxNode, SyntaxNode) ProcessNodes(SyntaxNode root, SyntaxNode processingNode, List <ChangeMember> childs) { Dictionary <SyntaxNode, SyntaxNode> GetFilteredNodes(List <ChangeMember> innerChilds, Func <ChangeMember, bool> filterFunc, Func <ChangeMember, (SyntaxNode, SyntaxNode)> transformFunc) { return(innerChilds.Where(filterFunc).Select(transformFunc).ToDictionary(p => p.Item1, p => p.Item2)); } SyntaxNode newProcessingNode = null; SyntaxNode newRemovedNode = null; var replaceNodes = GetFilteredNodes(childs, m => m.OldMember != null && m.NewMember != null, c => (root.GetCurrentNode(c.OldMember), c.NewMember.TrackNodes(c.NewMember.DescendantNodesAndSelf()))); if (replaceNodes.Any()) { newProcessingNode = childs.FirstOrDefault(m => m.OldMember != null && m.NewMember != null && m.OldMember == processingNode)?.NewMember; root = root.ReplaceNodes(replaceNodes.Keys, (o, r) => replaceNodes[o]); } var removeNodes = GetFilteredNodes(childs, m => m.OldMember != null && m.NewMember == null, c => (root.GetCurrentNode(c.OldMember), null)); if (removeNodes.Any()) { newRemovedNode = childs.FirstOrDefault(m => m.OldMember != null && m.NewMember == null)?.OldMember; root = root.RemoveNodes(removeNodes.Keys, SyntaxRemoveOptions.KeepNoTrivia); } var insertNodes = GetFilteredNodes(childs, m => m.OldMember == null && m.NewMember != null, c => (c.NewMember.TrackNodes(c.NewMember.DescendantNodesAndSelf()), c.BaseMember)); foreach (var addNode in insertNodes.Keys) { var baseNode = insertNodes[addNode]; if (baseNode == null) { baseNode = root.ChildNodes().OfType <MemberDeclarationSyntax>().Last(); } else { baseNode = root.GetCurrentNode(baseNode); } Logger.Info($"BaseNode type = {baseNode?.GetType()}"); root = root.InsertNodesAfter(baseNode, new[] { addNode }); } if (newProcessingNode != null) { newProcessingNode = root.GetCurrentNode(newProcessingNode); } else { newProcessingNode = newRemovedNode != null ? null : processingNode; } return(root, newProcessingNode); } if (workNode == null) { return(null, null, null, null, false, null); } var richGeneratorResult = new RichGenerationResult(); var newMemberNode = workNode; if (workNode is CompilationUnitSyntax || workNode is NamespaceDeclarationSyntax || workNode is TypeDeclarationSyntax) { var rootNodeIsType = workNode is TypeDeclarationSyntax; foreach (var node in workNode.ChildNodes() .Where(n => n is CompilationUnitSyntax || n is NamespaceDeclarationSyntax || n is TypeDeclarationSyntax || rootNodeIsType) .OfType <CSharpSyntaxNode>().ToList()) { var processedNode = node as SyntaxNode; var innerNodesReplacement = await ProcessNodeTransformation(compilation, semanticModel, rootNode, rootNodeTracked, treeChanged, node); compilation = innerNodesReplacement.compilation; semanticModel = innerNodesReplacement.semanticModel; rootNode = innerNodesReplacement.resRootNode; rootNodeTracked = innerNodesReplacement.resRootNodeTracked; treeChanged = innerNodesReplacement.treeChanged; richGeneratorResult.Externs = richGeneratorResult.Externs.AddRange(innerNodesReplacement.richGenerationResult.Externs); richGeneratorResult.Usings = richGeneratorResult.Usings.AddRange(innerNodesReplacement.richGenerationResult.Usings); richGeneratorResult.AttributeLists = richGeneratorResult.AttributeLists.AddRange(innerNodesReplacement.richGenerationResult.AttributeLists); richGeneratorResult.Members.AddRange(innerNodesReplacement.richGenerationResult.Members); } } newMemberNode = rootNode.GetCurrentNode(workNode) ?? workNode; var attributeData = GetAttributeData(compilation, semanticModel, newMemberNode); var generators = FindCodeGenerators(generatorKnownTypes, attributeData, assemblyLoader).ToList(); if (generators.Count > 0) { Logger.Info($"Generators founded = {generators.Count}"); } foreach (var generator in generators) { var context = new TransformationContext( newMemberNode, semanticModel, compilation, projectDirectory, emittedUsings, emittedExterns); var richGenerator = generator as IRichCodeGenerator ?? new EnrichingCodeGeneratorProxy(generator); var emitted = await richGenerator.GenerateRichAsync(context, progress, CancellationToken.None); Logger.Info($"Processed generator = {generator.GetType()}, node = {newMemberNode}, members count = {emitted.Members.Count}"); foreach (var member in emitted.Members) { Logger.Info($"member " + $"OldMember type = {member.OldMember?.GetType()}, OldMember value = {member.OldMember}" + $"BaseMember type = {member.BaseMember?.GetType()}, BaseMember value = {member.BaseMember}" + $"NewMember type = {member.NewMember?.GetType()}, NewMember value = {member.NewMember}"); } if (!treeChanged) { treeChanged = emitted.Members.Any(m => !(m.OldMember == null && m.BaseMember == null)); Logger.Info($"treeChanged={treeChanged}"); } var oldRootNode = rootNode; (rootNode, newMemberNode) = ProcessNodes(rootNodeTracked, newMemberNode, emitted.Members); rootNodeTracked = rootNode.TrackNodes(rootNode.DescendantNodesAndSelf()); compilation = compilation.ReplaceSyntaxTree(oldRootNode.SyntaxTree, rootNode.SyntaxTree); semanticModel = compilation.GetSemanticModel(rootNode.SyntaxTree); richGeneratorResult.Externs = richGeneratorResult.Externs.AddRange(emitted.Externs); richGeneratorResult.Usings = richGeneratorResult.Usings.AddRange(emitted.Usings); richGeneratorResult.AttributeLists = richGeneratorResult.AttributeLists.AddRange(emitted.AttributeLists); richGeneratorResult.Members.AddRange(emitted.Members.Where(m => m.OldMember == null && m.BaseMember == null)); // Check current node removed if (newMemberNode != null) { newMemberNode = rootNode.GetCurrentNode(newMemberNode) ?? newMemberNode; } else { break; } } return(compilation, semanticModel, rootNode, rootNodeTracked, treeChanged, richGeneratorResult); } var oldDocumentRootNode = inputDocument.GetRoot() as CSharpSyntaxNode; var documentRootNode = oldDocumentRootNode.TrackNodes(oldDocumentRootNode.DescendantNodesAndSelf()); var processNodeResult = await ProcessNodeTransformation(csCompilation, inputSemanticModel, oldDocumentRootNode, documentRootNode, false, oldDocumentRootNode); var emittedMembers = processNodeResult.treeChanged ? processNodeResult.resRootNode.ChildNodes().OfType <MemberDeclarationSyntax>().ToImmutableArray() : processNodeResult.richGenerationResult.Members.Where(m => m.NewMember != null).Select(m => m.NewMember).OfType <MemberDeclarationSyntax>().ToImmutableArray(); var compilationUnit = SyntaxFactory.CompilationUnit( SyntaxFactory.List(emittedExterns.AddRange(processNodeResult.richGenerationResult.Externs)), SyntaxFactory.List(emittedUsings.AddRange(processNodeResult.richGenerationResult.Usings)), SyntaxFactory.List(processNodeResult.richGenerationResult.AttributeLists), SyntaxFactory.List(emittedMembers)) .WithLeadingTrivia(SyntaxFactory.Comment(GeneratedByAToolPreamble)) .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed) .NormalizeWhitespace(); return(compilationUnit.SyntaxTree, processNodeResult.treeChanged); }