//===--- tools/extra/clang-rename/USRFindingAction.cpp - Clang rename tool ===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Provides an action to rename every symbol at a point. /// //===----------------------------------------------------------------------===// #include "USRFindingAction.h" #include "USRFinder.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Tooling.h" #include #include #include #include #include using namespace llvm; namespace clang { namespace rename { // Get the USRs for the constructors of the class. static std::vector getAllConstructorUSRs( const CXXRecordDecl *Decl) { std::vector USRs; // We need to get the definition of the record (as opposed to any forward // declarations) in order to find the constructor and destructor. const auto *RecordDecl = Decl->getDefinition(); // Iterate over all the constructors and add their USRs. for (const auto *CtorDecl : RecordDecl->ctors()) USRs.push_back(getUSRForDecl(CtorDecl)); // Ignore destructors. GetLocationsOfUSR will find the declaration of and // explicit calls to a destructor through TagTypeLoc (and it is better for the // purpose of renaming). // // For example, in the following code segment, // 1 class C { // 2 ~C(); // 3 }; // At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc starting // from 'C'. return USRs; } struct NamedDeclFindingConsumer : public ASTConsumer { void HandleTranslationUnit(ASTContext &Context) override { const auto &SourceMgr = Context.getSourceManager(); // The file we look for the USR in will always be the main source file. const auto Point = SourceMgr.getLocForStartOfFile( SourceMgr.getMainFileID()).getLocWithOffset(SymbolOffset); if (!Point.isValid()) return; const NamedDecl *FoundDecl = getNamedDeclAt(Context, Point); if (FoundDecl == nullptr) { FullSourceLoc FullLoc(Point, SourceMgr); errs() << "clang-rename: could not find symbol at " << SourceMgr.getFilename(Point) << ":" << FullLoc.getSpellingLineNumber() << ":" << FullLoc.getSpellingColumnNumber() << " (offset " << SymbolOffset << ").\n"; return; } // If the decl is a constructor or destructor, we want to instead take the // decl of the parent record. if (const auto *CtorDecl = dyn_cast(FoundDecl)) FoundDecl = CtorDecl->getParent(); else if (const auto *DtorDecl = dyn_cast(FoundDecl)) FoundDecl = DtorDecl->getParent(); // If the decl is in any way relatedpp to a class, we want to make sure we // search for the constructor and destructor as well as everything else. if (const auto *Record = dyn_cast(FoundDecl)) *USRs = getAllConstructorUSRs(Record); USRs->push_back(getUSRForDecl(FoundDecl)); *SpellingName = FoundDecl->getNameAsString(); } unsigned SymbolOffset; std::string *SpellingName; std::vector *USRs; }; std::unique_ptr USRFindingAction::newASTConsumer() { std::unique_ptr Consumer( new NamedDeclFindingConsumer); SpellingName = ""; Consumer->SymbolOffset = SymbolOffset; Consumer->USRs = &USRs; Consumer->SpellingName = &SpellingName; return std::move(Consumer); } } // namespace rename } // namespace clang