18 #include "clang/AST/AST.h"
19 #include "clang/AST/ASTConsumer.h"
20 #include "clang/AST/ASTContext.h"
21 #include "clang/AST/Decl.h"
22 #include "clang/AST/RecursiveASTVisitor.h"
23 #include "clang/Basic/FileManager.h"
24 #include "clang/Frontend/CompilerInstance.h"
25 #include "clang/Frontend/FrontendAction.h"
26 #include "clang/Lex/Lexer.h"
27 #include "clang/Lex/Preprocessor.h"
28 #include "clang/Tooling/CommonOptionsParser.h"
29 #include "clang/Tooling/Refactoring.h"
30 #include "clang/Tooling/Tooling.h"
47 class AdditionalUSRFinder :
public RecursiveASTVisitor<AdditionalUSRFinder> {
50 : FoundDecl(FoundDecl), Context(Context) {}
52 std::vector<std::string> Find() {
54 TraverseDecl(
Context.getTranslationUnitDecl());
55 if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(
FoundDecl)) {
56 addUSRsOfOverridenFunctions(MethodDecl);
58 if (checkIfOverriddenFunctionAscends(OverriddenMethod))
61 }
else if (
const auto *RecordDecl = dyn_cast<CXXRecordDecl>(
FoundDecl)) {
62 handleCXXRecordDecl(RecordDecl);
63 }
else if (
const auto *TemplateDecl =
65 handleClassTemplateDecl(TemplateDecl);
69 return std::vector<std::string>(
USRSet.begin(),
USRSet.end());
72 bool VisitCXXMethodDecl(
const CXXMethodDecl *MethodDecl) {
73 if (MethodDecl->isVirtual())
74 OverriddenMethods.push_back(MethodDecl);
78 bool VisitClassTemplatePartialSpecializationDecl(
79 const ClassTemplatePartialSpecializationDecl *PartialSpec) {
85 void handleCXXRecordDecl(
const CXXRecordDecl *RecordDecl) {
86 RecordDecl = RecordDecl->getDefinition();
87 if (
const auto *ClassTemplateSpecDecl =
88 dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
89 handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate());
90 addUSRsOfCtorDtors(RecordDecl);
93 void handleClassTemplateDecl(
const ClassTemplateDecl *TemplateDecl) {
94 for (
const auto *Specialization : TemplateDecl->specializations())
95 addUSRsOfCtorDtors(Specialization);
98 if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
99 addUSRsOfCtorDtors(PartialSpec);
101 addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
104 void addUSRsOfCtorDtors(
const CXXRecordDecl *RecordDecl) {
105 RecordDecl = RecordDecl->getDefinition();
107 for (
const auto *CtorDecl : RecordDecl->ctors())
114 void addUSRsOfOverridenFunctions(
const CXXMethodDecl *MethodDecl) {
117 for (
const auto &OverriddenMethod : MethodDecl->overridden_methods())
118 addUSRsOfOverridenFunctions(OverriddenMethod);
121 bool checkIfOverriddenFunctionAscends(
const CXXMethodDecl *MethodDecl) {
122 for (
const auto &OverriddenMethod : MethodDecl->overridden_methods()) {
125 return checkIfOverriddenFunctionAscends(OverriddenMethod);
134 std::vector<const ClassTemplatePartialSpecializationDecl *>
PartialSpecs;
142 std::vector<std::string> &SpellingNames,
143 std::vector<std::vector<std::string>> &USRList,
145 : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
146 SpellingNames(SpellingNames), USRList(USRList),
147 ErrorOccurred(ErrorOccurred) {}
151 unsigned SymbolOffset,
const std::string &QualifiedName) {
152 DiagnosticsEngine &Engine = Context.getDiagnostics();
153 const FileID MainFileID = SourceMgr.getMainFileID();
155 if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
156 ErrorOccurred =
true;
157 unsigned InvalidOffset = Engine.getCustomDiagID(
158 DiagnosticsEngine::Error,
159 "SourceLocation in file %0 at offset %1 is invalid");
160 Engine.Report(SourceLocation(), InvalidOffset)
161 << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset;
165 const SourceLocation
Point = SourceMgr.getLocForStartOfFile(MainFileID)
166 .getLocWithOffset(SymbolOffset);
167 const NamedDecl *
FoundDecl = QualifiedName.empty()
171 if (FoundDecl ==
nullptr) {
172 if (QualifiedName.empty()) {
173 FullSourceLoc FullLoc(Point, SourceMgr);
174 unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
175 DiagnosticsEngine::Error,
176 "clang-rename could not find symbol (offset %0)");
177 Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
178 ErrorOccurred =
true;
181 unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
182 DiagnosticsEngine::Error,
"clang-rename could not find symbol %0");
183 Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
184 ErrorOccurred =
true;
190 if (
const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
191 FoundDecl = CtorDecl->getParent();
192 else if (
const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
193 FoundDecl = DtorDecl->getParent();
195 SpellingNames.push_back(FoundDecl->getNameAsString());
196 AdditionalUSRFinder
Finder(FoundDecl, Context);
197 USRList.push_back(
Finder.Find());
201 void HandleTranslationUnit(ASTContext &Context)
override {
202 const SourceManager &SourceMgr = Context.getSourceManager();
204 if (!FindSymbol(Context, SourceMgr, Offset,
""))
208 if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
215 std::vector<std::string> &SpellingNames;
216 std::vector<std::vector<std::string>> &USRList;
220 std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
221 return llvm::make_unique<NamedDeclFindingConsumer>(
const SourceLocation Point
std::unique_ptr< ast_matchers::MatchFinder > Finder
const NamedDecl * getNamedDeclAt(const ASTContext &Context, const SourceLocation Point)
std::string getUSRForDecl(const Decl *Decl)
std::vector< const CXXMethodDecl * > OverriddenMethods
NamedDeclFindingConsumer(ArrayRef< unsigned > SymbolOffsets, ArrayRef< std::string > QualifiedNames, std::vector< std::string > &SpellingNames, std::vector< std::vector< std::string >> &USRList, bool &ErrorOccurred)
Provides an action to find all relevant USRs at a point.
Methods for determining the USR of a symbol at a location in source code.
const NamedDecl * getNamedDeclFor(const ASTContext &Context, const std::string &Name)
static cl::list< std::string > QualifiedNames("qualified-name", cl::desc("The fully qualified name of the symbol."), cl::ZeroOrMore, cl::cat(ClangRenameOptions))
static cl::list< unsigned > SymbolOffsets("offset", cl::desc("Locates the symbol by offset as opposed to <line>:<column>."), cl::ZeroOrMore, cl::cat(ClangRenameOptions))
std::set< std::string > USRSet
std::vector< const ClassTemplatePartialSpecializationDecl * > PartialSpecs