我可以使用Roslyn DocumentEditor将语句插入到空函数体中吗

时间:2019-02-16 06:31:56

标签: visual-studio roslyn

在Visual Studio扩展中,我正在使用DocumentEditor(Microsoft.CodeAnalysis.Editing.DocumentEditor)类对源文件进行多次更新。

其中一项更改是将构造函数添加到类中。构造函数必须具有特定的参数,该参数通过依赖项注入传递,并且必须将参数保存到成员变量中。 如果构造函数已经存在,则应检查参数并检查赋值语句。

大多数方法都有效,但是如果我必须向空函数添加一条语句,则会出现问题。

如果构造函数已经存在并且包含一些语句,我可以添加一个新语句

RoslynEditor.InsertBefore ( cons.Body.Statements.First(), assExpr ) ;

如果构造函数存在,但为空,则此构造将不起作用。到目前为止,我还没有找到使用DocumentEditor类将语句插入到空函数体中的任何方法。

目前,我选择了大锤方法,使用DocumentEditor.ReplaceNode替换完整的构造方法。

那么有没有办法(如果主体为空)使用DocumentEditor类将语句插入到函数主体中?

这是我的代码的一部分。 _RoslynUtilCS中的函数仅返回一些roslyn语法。

// Look for the constructor
var cons = c.DescendantNodes().OfType<ConstructorDeclarationSyntax>().FirstOrDefault() ;
if ( cons == null )
{
  // There is no constructor.
  cons = _RoslynUtilCS.ControllerConstructor ( ShortClassName )
                      .WithAdditionalAnnotations ( Formatter.Annotation )
                      .WithTrailingTrivia ( _RoslynUtilCS.LineFeedSyntax() ) ;

  RoslynEditor.InsertBefore ( c.Members.First(), cons ) ;
}
else
{
  string parameterName = null ;

  // There is a constructor.
  // Does it already have a parameter of the generic IStringLocalizer type
  foreach ( var p in cons.ParameterList.Parameters )
  {
    var t  = p.Type ;
    var gt = t as GenericNameSyntax ;
    if ( gt != null )
    {
      if ( gt.Identifier.ToString() == "IStringLocalizer" )
      {
        parameterName = p.Identifier.ToString() ;
      }
    }
  }

  if ( string.IsNullOrEmpty ( parameterName ) )
  {
    // Add a parameter
    var param = _RoslynUtilCS.LocalizerParameter ( ShortClassName ) ;
    RoslynEditor.AddParameter ( cons, param ) ;

    // Add an assignment statement to assign the parameter to the localizer member variable.
    var assExpr = _RoslynUtilCS.LocalizerAsignment()
                               .WithAdditionalAnnotations ( Formatter.Annotation ) ;

    if ( cons.Body.Statements.Count == 0 )
    {
      // -------------------------------------------------------------------
      // Here I replace the complete constructor.
      // because I don't know how to insert a statement into
      // the empty constructor body.
      // -------------------------------------------------------------------
      var newcons = _RoslynUtilCS.ControllerConstructor ( ShortClassName )
                                 .WithAdditionalAnnotations ( Formatter.Annotation )
                                 .WithTrailingTrivia ( _RoslynUtilCS.LineFeedSyntax() ) ;

      RoslynEditor.ReplaceNode ( cons, newcons ) ;
    }
    else
    {
      RoslynEditor.InsertBefore ( cons.Body.Statements.First(), assExpr ) ;
    }
  }
  else
  {
    // NOT TESTED
    // It seems a bit over the top, but having found a parameter, we should look
    // for an assignment to the member variable and add it if it is missing.
    var count = cons.DescendantNodes()
                    .OfType<AssignmentExpressionSyntax>()
                    .Where(node => node.Kind() == SyntaxKind.SimpleAssignmentExpression)
                    .Where(node => node.Left.ToString() == "_localizer")
                    .Where(node => node.Right.ToString() == "localizer")
                    .Count() ;
    if ( count == 0 )
    {
      // Add an assignment statement to assign the parameter to the localizer member variable.
      var assExpr = _RoslynUtilCS.LocalizerAsignment() ;

      // -------------------------------------------------------------------
      // This is likely to have the same problem.
      // It won't work if the body contains no statements.
      // -------------------------------------------------------------------
      RoslynEditor.InsertBefore ( cons.Body.Statements.First(), assExpr ) ;
    }
  }
}

1 个答案:

答案 0 :(得分:1)

最终,编辑器的

InsertAdd方法是InsertMembers的{​​{1}},无论如何他们用新的AKA SyntaxGenerator替换了原始节点。

检查此方法的source code,您将看到插入成员以0个成员的方式阻止主体(对于Replace而言)是返回声明本身而没有更改,这就是为什么您不能做简单的ConstructorDeclarationSyntax

您可以定义一个新的扩展方法来为您执行此操作,或者编写类似这样的内容来替换主体:

editor.Insert\Add..

editor.ReplaceNode(ctor.Body, SyntaxFactory.Block(newStatement));