C# Roslyn-通过替换语法根中的文本范围来修复文档中的错误

C# Roslyn-通过替换语法根中的文本范围来修复文档中的错误,c#,roslyn,diagnostics,roslyn-code-analysis,C#,Roslyn,Diagnostics,Roslyn Code Analysis,我这里有一点特别,基本上,我在一个临时工作区中加载,并在编译中得到与特定值相关的错误,因为我确切地知道需要替换什么文本,但不知道在哪里。代码如下 public static async Task<Solution> UpdateEntityReferences(Solution solution, ProjectId servicesId, string oldValue, string newValue) { var project = solution.GetProje

我这里有一点特别,基本上,我在一个临时工作区中加载,并在编译中得到与特定值相关的错误,因为我确切地知道需要替换什么文本,但不知道在哪里。代码如下

public static async Task<Solution> UpdateEntityReferences(Solution solution, ProjectId servicesId, string oldValue, string newValue)
{
     var project = solution.GetProject(servicesId);
     var compilation = await project.GetCompilationAsync();
     var diagnostics = compilation.GetDiagnostics().Where(diag => diag.GetMessage().Contains($"'{oldValue}'"));

     foreach (var diagnostic in diagnostics)
     {
         var errorLineSpan = diagnostic.Location.GetLineSpan();
         var document = project.FindDocumentByName(Path.GetFileName(errorLineSpan.Path));
         var syntaxRoot = await document.GetSyntaxRootAsync();
         var errorSpan = errorLineSpan.Span;
     }
     return solution;
}

文本被替换(有一半的时间被错误地替换),然后剩下一个SourceText对象,我不知道如何在文档中替换它。有什么想法吗?

最后到达了那里-因此您不能在不使用类似的东西的情况下替换文本span并取回文档,因为您需要替换SyntaxNode,并且不能保证LineSpan的字符位置仍然正确,因为节点被抓取

解决方案只是使用LineSpan中的行号来获取该行上的节点,然后使用LINQ向下过滤到令牌。一旦抓取了确切的节点,就可以在父节点、syntaxRoot和文档中替换它。代码如下

foreach (var diagnostic in diagnostics)
{
     servicesProject = solution.GetProject(servicesId);
     var errorLineSpan = diagnostic.Location.GetLineSpan();
     var document = servicesProject.FindDocumentByName(Path.GetFileName(errorLineSpan.Path));
     var syntaxTree = await document.GetSyntaxTreeAsync();
     var errorSpan = errorLineSpan.Span;
     var lineSpan = syntaxTree.GetText().Lines[errorSpan.Start.Line].Span;

     var node = syntaxTree.GetRoot().DescendantNodes(lineSpan)
.First(n => lineSpan.Contains(n.FullSpan)).DescendantNodes()
.OfType<IdentifierNameSyntax>().FirstOrDefault(c => c.Identifier.Text == oldValue);

        var newNode = node.ReplaceNode(node, SyntaxFactory.IdentifierName(newValue));
        var newSyntaxRoot = syntaxTree.GetRoot().ReplaceNode(node, newNode);
        document = document.WithSyntaxRoot(newSyntaxRoot);
        solution = document.Project.Solution;           
}
foreach(诊断中的var诊断)
{
servicesProject=solution.GetProject(servicesId);
var errorLineSpan=diagnostic.Location.GetLineSpan();
var document=servicesProject.FindDocumentByName(Path.GetFileName(errorLineSpan.Path));
var syntaxTree=await document.GetSyntaxTreeAsync();
var errorSpan=errorLineSpan.Span;
var lineSpan=syntaxTree.GetText().Lines[errorSpan.Start.Line].Span;
var node=syntaxTree.GetRoot().degenantnodes(lineSpan)
.First(n=>lineSpan.Contains(n.FullSpan)).genderantnodes()
.OfType().FirstOrDefault(c=>c.Identifier.Text==oldValue);
var newNode=node.ReplaceNode(node,SyntaxFactory.IdentifierName(newValue));
var newSyntaxRoot=syntaxTree.GetRoot().ReplaceNode(节点,newNode);
document=document.WithSyntaxRoot(newSyntaxRoot);
解决方案=document.Project.solution;
}

如果您只是简单地将-而不将其分配给errorSpan,会发生什么情况?@nuriselcuk它会抛出一个错误,因为我将尝试将字符串分配给LinePositionSpan,我可能无法从中取回文档。将LinePositionSpan字符串怎么样?我确定您要使用
document.WithText(SourceText text)
获取文档的新版本,然后使用
Project.RemoveDocument(…)
删除旧版本和
Project.AddDocument(…)
添加新代码。顺便说一下,如果您尝试编写自定义代码修复提供程序,最好是修复文档,而不是文档solution@GeorgeAlexandria我可能正在修改语法节点,需要替换文档的语法根。我需要找出如何替换编译错误诊断中的文本范围我会在那之后取回完整的文件
foreach (var diagnostic in diagnostics)
{
     servicesProject = solution.GetProject(servicesId);
     var errorLineSpan = diagnostic.Location.GetLineSpan();
     var document = servicesProject.FindDocumentByName(Path.GetFileName(errorLineSpan.Path));
     var syntaxTree = await document.GetSyntaxTreeAsync();
     var errorSpan = errorLineSpan.Span;
     var lineSpan = syntaxTree.GetText().Lines[errorSpan.Start.Line].Span;

     var node = syntaxTree.GetRoot().DescendantNodes(lineSpan)
.First(n => lineSpan.Contains(n.FullSpan)).DescendantNodes()
.OfType<IdentifierNameSyntax>().FirstOrDefault(c => c.Identifier.Text == oldValue);

        var newNode = node.ReplaceNode(node, SyntaxFactory.IdentifierName(newValue));
        var newSyntaxRoot = syntaxTree.GetRoot().ReplaceNode(node, newNode);
        document = document.WithSyntaxRoot(newSyntaxRoot);
        solution = document.Project.Solution;           
}