1 //===--- RenamingAction.cpp - Clang refactoring library -------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief Provides an action to rename every symbol at a point. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/Tooling/Refactoring/Rename/RenamingAction.h" 16 #include "clang/AST/ASTConsumer.h" 17 #include "clang/AST/ASTContext.h" 18 #include "clang/Basic/FileManager.h" 19 #include "clang/Frontend/CompilerInstance.h" 20 #include "clang/Frontend/FrontendAction.h" 21 #include "clang/Lex/Lexer.h" 22 #include "clang/Lex/Preprocessor.h" 23 #include "clang/Tooling/CommonOptionsParser.h" 24 #include "clang/Tooling/Refactoring.h" 25 #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" 26 #include "clang/Tooling/Tooling.h" 27 #include <string> 28 #include <vector> 29 30 using namespace llvm; 31 32 namespace clang { 33 namespace tooling { 34 35 class RenamingASTConsumer : public ASTConsumer { 36 public: 37 RenamingASTConsumer( 38 const std::vector<std::string> &NewNames, 39 const std::vector<std::string> &PrevNames, 40 const std::vector<std::vector<std::string>> &USRList, 41 std::map<std::string, tooling::Replacements> &FileToReplaces, 42 bool PrintLocations) 43 : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList), 44 FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {} 45 46 void HandleTranslationUnit(ASTContext &Context) override { 47 for (unsigned I = 0; I < NewNames.size(); ++I) 48 HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]); 49 } 50 51 void HandleOneRename(ASTContext &Context, const std::string &NewName, 52 const std::string &PrevName, 53 const std::vector<std::string> &USRs) { 54 const SourceManager &SourceMgr = Context.getSourceManager(); 55 std::vector<SourceLocation> RenamingCandidates; 56 std::vector<SourceLocation> NewCandidates; 57 58 NewCandidates = tooling::getLocationsOfUSRs( 59 USRs, PrevName, Context.getTranslationUnitDecl()); 60 RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(), 61 NewCandidates.end()); 62 63 unsigned PrevNameLen = PrevName.length(); 64 for (const auto &Loc : RenamingCandidates) { 65 if (PrintLocations) { 66 FullSourceLoc FullLoc(Loc, SourceMgr); 67 errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc) 68 << ":" << FullLoc.getSpellingLineNumber() << ":" 69 << FullLoc.getSpellingColumnNumber() << "\n"; 70 } 71 // FIXME: better error handling. 72 tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName); 73 llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); 74 if (Err) 75 llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " 76 << llvm::toString(std::move(Err)) << "\n"; 77 } 78 } 79 80 private: 81 const std::vector<std::string> &NewNames, &PrevNames; 82 const std::vector<std::vector<std::string>> &USRList; 83 std::map<std::string, tooling::Replacements> &FileToReplaces; 84 bool PrintLocations; 85 }; 86 87 // A renamer to rename symbols which are identified by a give USRList to 88 // new name. 89 // 90 // FIXME: Merge with the above RenamingASTConsumer. 91 class USRSymbolRenamer : public ASTConsumer { 92 public: 93 USRSymbolRenamer(const std::vector<std::string> &NewNames, 94 const std::vector<std::vector<std::string>> &USRList, 95 std::map<std::string, tooling::Replacements> &FileToReplaces) 96 : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) { 97 assert(USRList.size() == NewNames.size()); 98 } 99 100 void HandleTranslationUnit(ASTContext &Context) override { 101 for (unsigned I = 0; I < NewNames.size(); ++I) { 102 // FIXME: Apply AtomicChanges directly once the refactoring APIs are 103 // ready. 104 auto AtomicChanges = tooling::createRenameAtomicChanges( 105 USRList[I], NewNames[I], Context.getTranslationUnitDecl()); 106 for (const auto AtomicChange : AtomicChanges) { 107 for (const auto &Replace : AtomicChange.getReplacements()) { 108 llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); 109 if (Err) { 110 llvm::errs() << "Renaming failed in " << Replace.getFilePath() 111 << "! " << llvm::toString(std::move(Err)) << "\n"; 112 } 113 } 114 } 115 } 116 } 117 118 private: 119 const std::vector<std::string> &NewNames; 120 const std::vector<std::vector<std::string>> &USRList; 121 std::map<std::string, tooling::Replacements> &FileToReplaces; 122 }; 123 124 std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() { 125 return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList, 126 FileToReplaces, PrintLocations); 127 } 128 129 std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() { 130 return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces); 131 } 132 133 } // end namespace tooling 134 } // end namespace clang 135