Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 5
0
        /// <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);
        }
Ejemplo n.º 6
0
        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));
            }
        }
Ejemplo n.º 8
0
        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);
        }