可以使用Roslyn API重命名源文件吗?

时间:2014-05-30 13:05:59

标签: visual-studio-2013 roslyn

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

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

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

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

我正在使用Visual Studio 2017和Code Refactoring 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