2

最初の段階で、構文ノードに注釈を追加し、ノードを新しく生成されたノードに置き換えます。

第 2 段階では、変更されたドキュメント (注釈が追加された同じ構文ツリー) を分析していますが、SymbolInfo の参照はまだ変更されていない構文ノード (注釈なし) を参照しています。

注釈を追加した後に、ソリューションまたはプロジェクトを更新または再解析し、S​​ymbolInfo を更新することは可能ですか?

1 つの 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 にある newIDocumentを作成して返します。IProjectこれは 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 に答える