| //===--- 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 <ctype.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string> |
| #include <vector> |
| |
| using namespace llvm; |
| |
| namespace clang { |
| namespace rename { |
| |
| // Get the USRs for the constructors of the class. |
| static std::vector<std::string> getAllConstructorUSRs( |
| const CXXRecordDecl *Decl) { |
| std::vector<std::string> 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<CXXConstructorDecl>(FoundDecl)) |
| FoundDecl = CtorDecl->getParent(); |
| else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(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<CXXRecordDecl>(FoundDecl)) |
| *USRs = getAllConstructorUSRs(Record); |
| |
| USRs->push_back(getUSRForDecl(FoundDecl)); |
| *SpellingName = FoundDecl->getNameAsString(); |
| } |
| |
| unsigned SymbolOffset; |
| std::string *SpellingName; |
| std::vector<std::string> *USRs; |
| }; |
| |
| std::unique_ptr<ASTConsumer> |
| USRFindingAction::newASTConsumer() { |
| std::unique_ptr<NamedDeclFindingConsumer> Consumer( |
| new NamedDeclFindingConsumer); |
| SpellingName = ""; |
| Consumer->SymbolOffset = SymbolOffset; |
| Consumer->USRs = &USRs; |
| Consumer->SpellingName = &SpellingName; |
| return std::move(Consumer); |
| } |
| |
| } // namespace rename |
| } // namespace clang |