添加命名空间与罗斯林CodeAnalyzer类 [英] Add Namespace to class with Roslyn CodeAnalyzer

查看:206
本文介绍了添加命名空间与罗斯林CodeAnalyzer类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

小猪釜底抽薪添加参数与罗斯林CodeFixProvider 的方法,



我正在创建一个 CodeFixProvider 的确保所有异步方法采取的CancellationToken

  //之前代码修复:
公共异步任务实例(){}

//代码修复
公共异步任务实例(令牌的CancellationToken){}

我可以将参数添加到方法,但我必须这样做,使用 Type.FullName 。相反,我想为的System.Threading 添加一个using语句类文件的顶部,这样的方法并不需要使用完整的命名空间。换句话说:

  //什么我迄今:
公共类ACLASS {
公共异步任务实例(System.Threading.CancellationToken令牌){}
}

//我想要什么:使用的System.Threading
;

公共类ACLASS {
公共异步任务实例(的CancellationToken令牌){}
}

我如何添加的使用的语句将文件



我已经尝试了几种方法,但是当我更换多个节点在 SyntaxTree 引用正在被它的接缝丢失(如树是不可变的,改在每一个变化)。



我能得到它的一部分与下面的代码的工作,但这只是工作,如果 CompilationUnitSyntax.Using 属性是填充,这是不是在使用语句来一个命名空间后的的情况。而这也依赖于那里是至少有一个使用语句已经在文件中。



有没有更好的方式来做到这一点?



 专用异步任务<文件> HaveMethodTakeACancellationTokenParameter(
文档文件,SyntaxNode syntaxNode,的CancellationToken的CancellationToken)
{
变种syntaxTree =
(等待document.GetSyntaxTreeAsync(的CancellationToken))
.GetRoot(的CancellationToken);

VAR方法= syntaxNode为MethodDeclarationSyntax;

#区域添加参数
变种newParameter =
SyntaxFactory.Parameter(
SyntaxFactory.Identifier(的CancellationToken)

.WithType (
SyntaxFactory.ParseTypeName(
typeof运算(的CancellationToken).FullName));

VAR updatedMethod = method.AddParameterListParameters(newParameter);

syntaxTree = syntaxTree.ReplaceNode(方法,updatedMethod);

#endregion

#区域添加using语句

变种编译=
syntaxTree为CompilationUnitSyntax;

变种systemThreadingUsingName =
SyntaxFactory.QualifiedName(
SyntaxFactory.IdentifierName(系统),
SyntaxFactory.IdentifierName(线程));

如果(compilation.Usings.All(U =方式>!u.Name.GetText()的ToString()= typeof运算(的CancellationToken).Namespace))
{
syntaxTree = syntaxTree.InsertNodesAfter(compilation.Usings.Last(),新的[]
{
SyntaxFactory.UsingDirective(
systemThreadingUsingName)
});
}

#endregion

返回document.WithSyntaxRoot(syntaxTree);
}


解决方案

一种选择是,以纪念所有与注释方法,添加using语句,找到注释的方法,改变所有的方法,并删除注释。



树是不可变的像你说的,但注解在修改不会丢失。所以,你需要类似如下:

  VAR注释=新SyntaxAnnotation(); 
VAR newRoot = root.ReplaceNode(
方法,
method.WithAdditionalAnnotations(注释));
newRoot = AddUsing(newRoot);
法= newRoot.GetAnnotatedNodes(注释)。首先();
VAR newMethod = ChangeParameters(法);
newRoot = root.ReplaceNode(方法,newMethod.WithoutAnnotations(注释));






全面实施:

 专用异步任务<文件> HaveMethodTakeACancellationTokenParameter(
文档文件,SyntaxNode syntaxNode,的CancellationToken的CancellationToken)
{
VAR方法= syntaxNode为MethodDeclarationSyntax;

变种cancellationTokenParameter =
SyntaxFactory.Parameter(
SyntaxFactory.Identifier(的CancellationToken)

.WithType(
SyntaxFactory.ParseTypeName (
typeof运算(的CancellationToken).Name点));

变种根=
(等待document.GetSyntaxTreeAsync(的CancellationToken))
.GetRoot(的CancellationToken);

变种注释=新SyntaxAnnotation();
VAR newRoot = root.ReplaceNode(
方法,
method.WithAdditionalAnnotations(注释));

#区域添加using语句

变种systemThreadingUsingStatement =
SyntaxFactory.UsingDirective(
SyntaxFactory.QualifiedName(
SyntaxFactory.IdentifierName(系统),
SyntaxFactory.IdentifierName(线程)));

变种编译=
newRoot为CompilationUnitSyntax;

如果(空==编译)
{
newRoot =
newRoot.InsertNodesBefore(
newRoot.ChildNodes()。首先(),
新的[] {systemThreadingUsingStatement});
}
,否则如果(compilation.Usings.All(U =方式>!u.Name.GetText()的ToString()= typeof运算(的CancellationToken).Namespace))
{
newRoot =
newRoot.InsertNodesAfter(compilation.Usings.Last(),
新的[] {systemThreadingUsingStatement});
}

#endregion

法=(MethodDeclarationSyntax)newRoot.GetAnnotatedNodes(注释)。首先();

VAR updatedMethod = method.AddParameterListParameters(cancellationTokenParameter);
newRoot = newRoot.ReplaceNode(方法,updatedMethod.WithoutAnnotations(注释));

返回document.WithSyntaxRoot(newRoot);
}


Piggy backing off Add a parameter to a method with a Roslyn CodeFixProvider,

I'm working on creating a CodeFixProvider that ensures all async methods take a CancellationToken:

//Before Code Fix:
public async Task Example(){}

//After Code Fix
public async Task Example(CancellationToken token){}

I'm able to add the parameter to the method, but I have to do so using the Type.FullName. Instead, I'd like to add a using statement for System.Threading to the top of the class file so the method doesn't need to use the full namespace. In other words:

// What I have thus far:
public class AClass{
  public async Task Example(System.Threading.CancellationToken token){}
}

// What I want:
using System.Threading;

public class AClass{
  public async Task Example(CancellationToken token){}
}

How can I add a using statement to a Document?

I've tried a couple ways, but it seams when I'm replacing multiple nodes in a SyntaxTree references are being lost (as the tree is immutable and reconstructed on every change).

I was able to get it partially working with the code below, but this only works if the CompilationUnitSyntax.Using property is populated, which is not the case when using statements come after a namespace. And this also relies on there being at least one using statement already in the file.

Is there a better way to do this?

private async Task<Document> HaveMethodTakeACancellationTokenParameter(
        Document document, SyntaxNode syntaxNode, CancellationToken cancellationToken)
    {
        var syntaxTree = 
            (await document.GetSyntaxTreeAsync(cancellationToken))
                .GetRoot(cancellationToken);

        var method = syntaxNode as MethodDeclarationSyntax;

        #region Add Parameter
        var newParameter =
            SyntaxFactory.Parameter(
                SyntaxFactory.Identifier("cancellationToken")
            )
            .WithType(
                SyntaxFactory.ParseTypeName(
                    typeof(CancellationToken).FullName));

        var updatedMethod = method.AddParameterListParameters(newParameter);

        syntaxTree = syntaxTree.ReplaceNode(method, updatedMethod);

        #endregion

        #region Add Using Statements

        var compilation =
            syntaxTree as CompilationUnitSyntax;                    

        var systemThreadingUsingName =
            SyntaxFactory.QualifiedName(
                SyntaxFactory.IdentifierName("System"),
                SyntaxFactory.IdentifierName("Threading"));

        if (compilation.Usings.All(u => u.Name.GetText().ToString() != typeof(CancellationToken).Namespace))
        {
            syntaxTree = syntaxTree.InsertNodesAfter(compilation.Usings.Last(), new[]
            {
                SyntaxFactory.UsingDirective(
                        systemThreadingUsingName)
            });
        }

        #endregion

        return document.WithSyntaxRoot(syntaxTree);
    }

解决方案

An option is to mark all methods with an annotation, add the using statement, find the methods with annotations, change all methods, and remove the annotations.

Trees are immutable as you said, but annotations are not lost during modifications. So you'll need something like the following:

var annotation = new SyntaxAnnotation();
var newRoot = root.ReplaceNode(
     method,
     method.WithAdditionalAnnotations(annotation));
newRoot = AddUsing(newRoot);
method = newRoot.GetAnnotatedNodes(annotation).First();
var newMethod = ChangeParameters(method);
newRoot = root.ReplaceNode(method, newMethod.WithoutAnnotations(annotation));


Full Implementation:

 private async Task<Document> HaveMethodTakeACancellationTokenParameter(
        Document document, SyntaxNode syntaxNode, CancellationToken cancellationToken)
    {
        var method = syntaxNode as MethodDeclarationSyntax;

        var cancellationTokenParameter =
           SyntaxFactory.Parameter(
               SyntaxFactory.Identifier("cancellationToken")
           )
           .WithType(
               SyntaxFactory.ParseTypeName(
                   typeof(CancellationToken).Name));

        var root = 
           (await document.GetSyntaxTreeAsync(cancellationToken))
               .GetRoot(cancellationToken);

        var annotation = new SyntaxAnnotation();
        var newRoot = root.ReplaceNode(
             method,
             method.WithAdditionalAnnotations(annotation));

        #region Add Using Statements

        var systemThreadingUsingStatement =
            SyntaxFactory.UsingDirective(
                SyntaxFactory.QualifiedName(
                    SyntaxFactory.IdentifierName("System"),
                    SyntaxFactory.IdentifierName("Threading")));

        var compilation =
            newRoot as CompilationUnitSyntax;

        if (null == compilation)
        {
            newRoot =
                newRoot.InsertNodesBefore(
                    newRoot.ChildNodes().First(),
                    new[] {systemThreadingUsingStatement});
        }
        else if (compilation.Usings.All(u => u.Name.GetText().ToString() != typeof(CancellationToken).Namespace))
        {
            newRoot = 
                newRoot.InsertNodesAfter(compilation.Usings.Last(), 
                new[]{ systemThreadingUsingStatement });
        }

        #endregion

        method = (MethodDeclarationSyntax)newRoot.GetAnnotatedNodes(annotation).First();

        var updatedMethod = method.AddParameterListParameters(cancellationTokenParameter);
        newRoot = newRoot.ReplaceNode(method, updatedMethod.WithoutAnnotations(annotation));

        return document.WithSyntaxRoot(newRoot);
    }

这篇关于添加命名空间与罗斯林CodeAnalyzer类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆