【问题标题】:Can one rename a source file using Roslyn APIs?可以使用 Roslyn API 重命名源文件吗?
【发布时间】:2017-09-22 00:37:42
【问题描述】:

我正在尝试使用新的 Roslyn 和 Visual Studio API 编写 UnmatchedClassAndFilename 诊断和代码修复程序。这个想法是重命名一个类或文件名,以防它们不相等。

如何使用 Roslyn API 在 Visual Studio 中重命名文件? Workspace 类似乎不支持这一点。

更新:在 CodePlex (https://roslyn.codeplex.com/workitem/258) 上创建了一个问题

【问题讨论】:

    标签: visual-studio-2013 roslyn


    【解决方案1】:

    不,Workspaces API 当前不支持此功能。这是一个常见的请求,但我不确定我们是否有明确跟踪该工作的内容,因此请随时在 CodePlex 上提交错误。

    【讨论】:

      【解决方案2】:

      我正在使用 Visual Studio 2017 和代码重构 VSIX 项目模板来完成此操作。

      这是我的代码:

      private async Task<Solution> ConvertTypeNameToPascalCaseAsync(Document document, TypeDeclarationSyntax typeDecl, CancellationToken cancellationToken)
      {
          // Produce a PascalCased version of the type declaration's identifier token.
          var identifierToken = typeDecl.Identifier;
          var newName = identifierToken.Text.ToPascalCase();
      
      
          // Get the symbol representing the type to be renamed.
          var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
          var typeSymbol = semanticModel.GetDeclaredSymbol(typeDecl, cancellationToken);
      
      
          // Produce a new solution that has all references to that type renamed, including the declaration.
          var originalSolution = document.Project.Solution;
          var optionSet = originalSolution.Workspace.Options;
          var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, typeSymbol, newName, optionSet, cancellationToken).ConfigureAwait(false);
          var newDocId = DocumentId.CreateNewId(document.Project.Id);
          var newText = await newSolution.GetDocument(document.Id).GetTextAsync(cancellationToken).ConfigureAwait(false);
          // rename document by adding a new document with the new name and removing the old document
          newSolution = newSolution.AddAdditionalDocument(newDocId, newName + ".cs", newText);
          newSolution = newSolution.RemoveDocument(document.Id);
      
          // Return the new solution with the now PascalCased type name.
          return newSolution;
      }
      

      注意:ToPascalCase() 是我添加到字符串类的扩展方法。

      需要注意的主要一点是,我使用AddAdditionalDocument()RemoveDocument() 有效地重命名了现有文档以匹配我的新名称。

      这是设置代码重构引擎的代码:

      public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
      {
          var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
      
          // Find the node at the selection.
          var node = root.FindNode(context.Span);
      
          // Only offer a refactoring if the selected node is a type declaration node.
          var typeDecl = node as TypeDeclarationSyntax;
          if (typeDecl == null)
          {
              return;
          }
      
          if (typeDecl.Identifier.Text.IsUpper())
          {
      
              // For any type declaration node, create a code action to reverse the identifier text.
              var action = CodeAction.Create("Convert type name to PascalCase", c => ConvertTypeNameToPascalCaseAsync(context.Document, typeDecl, c));
      
              // Register this code action.
              context.RegisterRefactoring(action);
          }
      }
      

      注意:IsUpper()也是我添加到字符串类的扩展方法。

      顺便说一下,我的具体用例是将所有带有下划线的大写类名转换为 PascalCased 类名。例子:

      TEST = Test

      TEST_CLASS = TestClass

      TEST_A_CLASS = TestAClass

      【讨论】:

      • 很高兴知道 3 年后有解决方案。如果您决定将此作为扩展发布,请告诉我们!
      • 我想你会想要 AddDocument 而不是 AddAdditionalDocument。附加文档适用于非源文件,但可供分析器和代码修复使用。
      猜你喜欢
      • 1970-01-01
      • 2022-01-27
      • 1970-01-01
      • 2014-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-24
      • 1970-01-01
      相关资源
      最近更新 更多