2

在第一阶段,我将注释添加到语法节点并用新生成的节点替换节点。

在第二阶段,当我分析修改后的文档(带有添加注释的相同语法树)但 SymbolInfo 中的引用仍然指的是未修改的语法节点(没有注释)。

添加注释后是否可以更新或重新解析解决方案或项目并更新 SymbolInfo?

使用一个 C# 文件创建简单的解决方案:

class С
{
    void g()
    { }

    void f()
    {
        g();
    }
}

并尝试用程序解析它:

using System.Collections.Generic;
using Roslyn.Compilers;
using Roslyn.Compilers.Common;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;

namespace RoslynExample2
{
    class Program
    {
        static void Main(string[] args)
        {
            var workspace = Workspace.LoadSolution(@"..\..\..\..\RoslynExampleTest\RoslynExampleTest.sln");
            var solution = workspace.CurrentSolution;

            foreach (var project in solution.Projects)
            {
                Annotator annotator = new Annotator();
                foreach (var document in project.Documents)
                {
                    CompilationUnitSyntax compilationUnit = (CompilationUnitSyntax)document.GetSyntaxRoot();
                    var mcu = annotator.AddAnnotations(compilationUnit);
                    document.UpdateSyntaxRoot(mcu);
                }
            }

            foreach (var project in solution.Projects)
            {
                foreach (var document in project.Documents)
                {
                    var compilationUnit = document.GetSyntaxRoot();
                    var semanticModel = document.GetSemanticModel();

                    MySyntaxWalker sw = new MySyntaxWalker(semanticModel);
                    sw.Visit((SyntaxNode)compilationUnit);
                }
            }
        }
    }

    internal class Annotator
    {
        internal struct SyntaxNodeTuple
        {
            internal SyntaxNode Origin;
            internal SyntaxNode Modified;

            internal SyntaxNodeTuple(SyntaxNode origin, SyntaxNode modified)
            {
                Origin = origin;
                Modified = modified;
            }
        }

        private SyntaxNodeTuple AddAnnotation(SyntaxNode s)
        {
            SyntaxNodeTuple t;

            switch (s.Kind)
            {
                case SyntaxKind.ClassDeclaration:
                    t = AddAnnotations((ClassDeclarationSyntax)s);
                    break;
                case SyntaxKind.MethodDeclaration:
                    t = AddAnnotations((MethodDeclarationSyntax)s);
                    break;
                default:
                    t = new SyntaxNodeTuple();
                    break;
            }

            return t;
        }

        private static T ReplaceNodes<T>(T d, List<SyntaxNodeTuple> tuples)
            where T : SyntaxNode
        {
            T d2 = d;
            foreach (var t in tuples)
            {
                d2 = d2.ReplaceNode(t.Origin, t.Modified);
            }
            return d2;
        }

        private void AddAnnotationsToList(SyntaxList<MemberDeclarationSyntax> list, List<SyntaxNodeTuple> tuples)
        {
            foreach (var m in list)
            {
                tuples.Add(AddAnnotation(m));
            }
        }

        internal CompilationUnitSyntax AddAnnotations(CompilationUnitSyntax d)
        {
            List<SyntaxNodeTuple> tuples = new List<SyntaxNodeTuple>();
            AddAnnotationsToList(d.Members, tuples);
            var d2 = ReplaceNodes(d, tuples);
            return d2;
        }

        internal SyntaxNodeTuple AddAnnotations(ClassDeclarationSyntax d)
        {
            List<SyntaxNodeTuple> tuples = new List<SyntaxNodeTuple>();
            AddAnnotationsToList(d.Members, tuples);
            var d2 = ReplaceNodes(d, tuples);
            d2 = d2.WithAdditionalAnnotations(new MyAnnotation());
            return new SyntaxNodeTuple(d, d2);
        }

        internal SyntaxNodeTuple AddAnnotations(MethodDeclarationSyntax d)
        {
            var d2 = d.WithAdditionalAnnotations(new MyAnnotation());

            bool hasAnnotation = d2.HasAnnotations(typeof(MyAnnotation)); // annotation exists

            return new SyntaxNodeTuple(d, d2);
        }
    }

    class MyAnnotation : SyntaxAnnotation
    { }

    partial class MySyntaxWalker : SyntaxWalker
    {
        private ISemanticModel _semanticModel;

        public MySyntaxWalker(ISemanticModel semanticModel)
        {
            _semanticModel = semanticModel;
        }

        public override void VisitInvocationExpression(InvocationExpressionSyntax decl)
        {
            var si = _semanticModel.GetSymbolInfo(decl);
            var dsns = si.Symbol.DeclaringSyntaxNodes;
            var dsn0 = dsns[0];
            bool hasAnnotation = dsn0.HasAnnotations(typeof(MyAnnotation));  // annotation doesn't exists
        }
    }
}

更新变体:

using System;
using System.Diagnostics;
using Roslyn.Compilers;
using Roslyn.Compilers.Common;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;

namespace RoslynExample2
{
    class Program
    {
        static void Main(string[] args)
        {
            var workspace = Workspace.LoadSolution(@"..\..\..\..\RoslynExampleTest\RoslynExampleTest.sln");
            var solution = workspace.CurrentSolution;

            foreach (var projectId in solution.ProjectIds)
            {
                var project = solution.GetProject(projectId);
                foreach (var documentId in project.DocumentIds)
                {
                    var document = project.GetDocument(documentId);
                    CompilationUnitSyntax compilationUnit = (CompilationUnitSyntax)document.GetSyntaxRoot();
                    Debug.WriteLine(String.Format("compilationUnit={0} before", compilationUnit.GetHashCode()));
                    Debug.WriteLine(String.Format("project={0} before", project.GetHashCode()));
                    Debug.WriteLine(String.Format("solution={0} before", solution.GetHashCode()));
                    var mcu = new AnnotatorSyntaxRewritter().Visit(compilationUnit);
                    var project2 = document.UpdateSyntaxRoot(mcu).Project;
                    if (mcu != compilationUnit)
                    {
                        solution = project2.Solution;
                    }
                    Debug.WriteLine(String.Format("compilationUnit={0} after", mcu.GetHashCode()));
                    Debug.WriteLine(String.Format("project={0} after", project2.GetHashCode()));
                    Debug.WriteLine(String.Format("solution={0} after", solution.GetHashCode()));
                }
            }

            foreach (var projectId in solution.ProjectIds)
            {
                var project = solution.GetProject(projectId);
                foreach (var documentId in project.DocumentIds)
                {
                    var document = project.GetDocument(documentId);
                    var compilationUnit = document.GetSyntaxRoot();
                    var semanticModel = document.GetSemanticModel();
                    Debug.WriteLine(String.Format("compilationUnit={0} stage", compilationUnit.GetHashCode()));
                    Debug.WriteLine(String.Format("project={0} stage", project.GetHashCode()));
                    Debug.WriteLine(String.Format("solution={0}", solution.GetHashCode()));

                    MySyntaxWalker sw = new MySyntaxWalker(semanticModel);
                    sw.Visit((SyntaxNode)compilationUnit);
                }
            }
        }
    }

    class AnnotatorSyntaxRewritter : SyntaxRewriter
    {
        public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
        {
            node = node.WithAdditionalAnnotations(new MyAnnotation());
            return base.VisitMethodDeclaration(node);
        }
    }

    class MyAnnotation : SyntaxAnnotation
    { }

    partial class MySyntaxWalker : SyntaxWalker
    {
        private ISemanticModel _semanticModel;

        public MySyntaxWalker(ISemanticModel semanticModel)
        {
            _semanticModel = semanticModel;
        }

        public override void VisitMethodDeclaration(MethodDeclarationSyntax decl)
        {
            bool hasAnnotation = decl.HasAnnotations(typeof(MyAnnotation));
            Debug.Assert(hasAnnotation);
        }
    }
}
4

1 回答 1

2

您的示例中的问题是该变量solution是一个不可变对象,它在首次加载时引用解决方案。在您调用的代码中document.UpdateSyntaxRoot(mcu),它实际上创建并返回一个 new IDocument,它位于 a newIProject中,位于 a new 中ISolution

尝试将那段代码更改为:

Annotator annotator = new Annotator();
foreach (var projectId in solution.ProjectIds)
{
    foreach (var documentId in solution.GetProject(projectId).DocumentIds)
    {
        var document = solution.GetProject(projectId).GetDocument(documentId);
        CompilationUnitSyntax compilationUnit = (CompilationUnitSyntax)document.GetSyntaxRoot();
        var mcu = annotator.AddAnnotations(compilationUnit);
        solution = document.UpdateSyntaxRoot(mcu).Project.Solution;
    }
}
于 2013-05-03T19:59:49.830 回答