Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 1 | //===--- tools/extra/clang-rename/USRFindingAction.cpp - Clang rename tool ===// |
| 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 |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 11 | /// \brief Provides an action to find USR for the symbol at <offset>, as well as |
| 12 | /// all additional USRs. |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 13 | /// |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #include "USRFindingAction.h" |
| 17 | #include "USRFinder.h" |
| 18 | #include "clang/AST/AST.h" |
| 19 | #include "clang/AST/ASTConsumer.h" |
| 20 | #include "clang/AST/ASTContext.h" |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 21 | #include "clang/AST/Decl.h" |
| 22 | #include "clang/AST/RecursiveASTVisitor.h" |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 23 | #include "clang/Basic/FileManager.h" |
| 24 | #include "clang/Frontend/CompilerInstance.h" |
| 25 | #include "clang/Frontend/FrontendAction.h" |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 26 | #include "clang/Lex/Lexer.h" |
Chandler Carruth | 3cbd71c | 2015-01-14 11:24:38 +0000 | [diff] [blame] | 27 | #include "clang/Lex/Preprocessor.h" |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 28 | #include "clang/Tooling/CommonOptionsParser.h" |
| 29 | #include "clang/Tooling/Refactoring.h" |
| 30 | #include "clang/Tooling/Tooling.h" |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 31 | |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 32 | #include <algorithm> |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 33 | #include <set> |
Kirill Bobyrev | 8100940 | 2016-08-04 09:23:30 +0000 | [diff] [blame] | 34 | #include <string> |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 35 | #include <vector> |
| 36 | |
| 37 | using namespace llvm; |
| 38 | |
| 39 | namespace clang { |
| 40 | namespace rename { |
| 41 | |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 42 | namespace { |
| 43 | // \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to |
| 44 | // AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given |
| 45 | // Decl refers to class and adds USRs of all overridden methods if Decl refers |
| 46 | // to virtual method. |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 47 | class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> { |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 48 | public: |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 49 | AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context) |
| 50 | : FoundDecl(FoundDecl), Context(Context) {} |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 51 | |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 52 | std::vector<std::string> Find() { |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 53 | // Fill OverriddenMethods and PartialSpecs storages. |
| 54 | TraverseDecl(Context.getTranslationUnitDecl()); |
Kirill Bobyrev | 91053e0 | 2016-08-01 17:15:57 +0000 | [diff] [blame] | 55 | if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) { |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 56 | addUSRsOfOverridenFunctions(MethodDecl); |
| 57 | for (const auto &OverriddenMethod : OverriddenMethods) { |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 58 | if (checkIfOverriddenFunctionAscends(OverriddenMethod)) |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 59 | USRSet.insert(getUSRForDecl(OverriddenMethod)); |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 60 | } |
| 61 | } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) { |
| 62 | handleCXXRecordDecl(RecordDecl); |
| 63 | } else if (const auto *TemplateDecl = |
Miklos Vajna | 0c07f0c | 2016-08-04 07:43:29 +0000 | [diff] [blame] | 64 | dyn_cast<ClassTemplateDecl>(FoundDecl)) { |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 65 | handleClassTemplateDecl(TemplateDecl); |
| 66 | } else { |
| 67 | USRSet.insert(getUSRForDecl(FoundDecl)); |
Kirill Bobyrev | 91053e0 | 2016-08-01 17:15:57 +0000 | [diff] [blame] | 68 | } |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 69 | return std::vector<std::string>(USRSet.begin(), USRSet.end()); |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 70 | } |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 71 | |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 72 | bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) { |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 73 | if (MethodDecl->isVirtual()) |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 74 | OverriddenMethods.push_back(MethodDecl); |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 75 | return true; |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 76 | } |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 77 | |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 78 | bool VisitClassTemplatePartialSpecializationDecl( |
| 79 | const ClassTemplatePartialSpecializationDecl *PartialSpec) { |
| 80 | PartialSpecs.push_back(PartialSpec); |
| 81 | return true; |
| 82 | } |
| 83 | |
| 84 | private: |
| 85 | void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) { |
| 86 | RecordDecl = RecordDecl->getDefinition(); |
Miklos Vajna | 0c07f0c | 2016-08-04 07:43:29 +0000 | [diff] [blame] | 87 | if (const auto *ClassTemplateSpecDecl = |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 88 | dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl)) |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 89 | handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate()); |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 90 | addUSRsOfCtorDtors(RecordDecl); |
| 91 | } |
| 92 | |
| 93 | void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) { |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 94 | for (const auto *Specialization : TemplateDecl->specializations()) |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 95 | addUSRsOfCtorDtors(Specialization); |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 96 | |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 97 | for (const auto *PartialSpec : PartialSpecs) { |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 98 | if (PartialSpec->getSpecializedTemplate() == TemplateDecl) |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 99 | addUSRsOfCtorDtors(PartialSpec); |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 100 | } |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 101 | addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl()); |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 102 | } |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 103 | |
Kirill Bobyrev | 91053e0 | 2016-08-01 17:15:57 +0000 | [diff] [blame] | 104 | void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) { |
| 105 | RecordDecl = RecordDecl->getDefinition(); |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 106 | |
Haojian Wu | 74f823a | 2017-04-04 09:30:06 +0000 | [diff] [blame] | 107 | // Skip if the CXXRecordDecl doesn't have definition. |
| 108 | if (!RecordDecl) |
| 109 | return; |
| 110 | |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 111 | for (const auto *CtorDecl : RecordDecl->ctors()) |
Kirill Bobyrev | 91053e0 | 2016-08-01 17:15:57 +0000 | [diff] [blame] | 112 | USRSet.insert(getUSRForDecl(CtorDecl)); |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 113 | |
Kirill Bobyrev | 91053e0 | 2016-08-01 17:15:57 +0000 | [diff] [blame] | 114 | USRSet.insert(getUSRForDecl(RecordDecl->getDestructor())); |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 115 | USRSet.insert(getUSRForDecl(RecordDecl)); |
Kirill Bobyrev | 91053e0 | 2016-08-01 17:15:57 +0000 | [diff] [blame] | 116 | } |
| 117 | |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 118 | void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) { |
Kirill Bobyrev | 91053e0 | 2016-08-01 17:15:57 +0000 | [diff] [blame] | 119 | USRSet.insert(getUSRForDecl(MethodDecl)); |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 120 | // Recursively visit each OverridenMethod. |
| 121 | for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 122 | addUSRsOfOverridenFunctions(OverriddenMethod); |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 123 | } |
| 124 | |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 125 | bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) { |
Kirill Bobyrev | 6b7d8c2 | 2016-08-15 23:20:05 +0000 | [diff] [blame] | 126 | for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) { |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 127 | if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 128 | return true; |
Kirill Bobyrev | d6ab7d4 | 2016-08-03 23:00:32 +0000 | [diff] [blame] | 129 | return checkIfOverriddenFunctionAscends(OverriddenMethod); |
| 130 | } |
| 131 | return false; |
| 132 | } |
| 133 | |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 134 | const Decl *FoundDecl; |
| 135 | ASTContext &Context; |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 136 | std::set<std::string> USRSet; |
Miklos Vajna | 0c07f0c | 2016-08-04 07:43:29 +0000 | [diff] [blame] | 137 | std::vector<const CXXMethodDecl *> OverriddenMethods; |
| 138 | std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs; |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 139 | }; |
| 140 | } // namespace |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 141 | |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 142 | class NamedDeclFindingConsumer : public ASTConsumer { |
| 143 | public: |
| 144 | NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets, |
| 145 | ArrayRef<std::string> QualifiedNames, |
| 146 | std::vector<std::string> &SpellingNames, |
| 147 | std::vector<std::vector<std::string>> &USRList, |
| 148 | bool &ErrorOccurred) |
| 149 | : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames), |
| 150 | SpellingNames(SpellingNames), USRList(USRList), |
| 151 | ErrorOccurred(ErrorOccurred) {} |
| 152 | |
| 153 | private: |
| 154 | bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr, |
| 155 | unsigned SymbolOffset, const std::string &QualifiedName) { |
| 156 | DiagnosticsEngine &Engine = Context.getDiagnostics(); |
Benjamin Kramer | 66039d3 | 2016-11-23 13:10:07 +0000 | [diff] [blame] | 157 | const FileID MainFileID = SourceMgr.getMainFileID(); |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 158 | |
Benjamin Kramer | 66039d3 | 2016-11-23 13:10:07 +0000 | [diff] [blame] | 159 | if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) { |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 160 | ErrorOccurred = true; |
| 161 | unsigned InvalidOffset = Engine.getCustomDiagID( |
| 162 | DiagnosticsEngine::Error, |
| 163 | "SourceLocation in file %0 at offset %1 is invalid"); |
Benjamin Kramer | 66039d3 | 2016-11-23 13:10:07 +0000 | [diff] [blame] | 164 | Engine.Report(SourceLocation(), InvalidOffset) |
| 165 | << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset; |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 166 | return false; |
Kirill Bobyrev | c2ed91f | 2016-09-14 13:00:36 +0000 | [diff] [blame] | 167 | } |
| 168 | |
Benjamin Kramer | 66039d3 | 2016-11-23 13:10:07 +0000 | [diff] [blame] | 169 | const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID) |
| 170 | .getLocWithOffset(SymbolOffset); |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 171 | const NamedDecl *FoundDecl = QualifiedName.empty() |
| 172 | ? getNamedDeclAt(Context, Point) |
| 173 | : getNamedDeclFor(Context, QualifiedName); |
| 174 | |
| 175 | if (FoundDecl == nullptr) { |
| 176 | if (QualifiedName.empty()) { |
| 177 | FullSourceLoc FullLoc(Point, SourceMgr); |
| 178 | unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID( |
| 179 | DiagnosticsEngine::Error, |
| 180 | "clang-rename could not find symbol (offset %0)"); |
| 181 | Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset; |
| 182 | ErrorOccurred = true; |
| 183 | return false; |
| 184 | } |
| 185 | unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID( |
| 186 | DiagnosticsEngine::Error, "clang-rename could not find symbol %0"); |
| 187 | Engine.Report(CouldNotFindSymbolNamed) << QualifiedName; |
| 188 | ErrorOccurred = true; |
| 189 | return false; |
| 190 | } |
| 191 | |
| 192 | // If FoundDecl is a constructor or destructor, we want to instead take |
| 193 | // the Decl of the corresponding class. |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 194 | if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl)) |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 195 | FoundDecl = CtorDecl->getParent(); |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 196 | else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl)) |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 197 | FoundDecl = DtorDecl->getParent(); |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 198 | |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 199 | SpellingNames.push_back(FoundDecl->getNameAsString()); |
| 200 | AdditionalUSRFinder Finder(FoundDecl, Context); |
| 201 | USRList.push_back(Finder.Find()); |
| 202 | return true; |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 203 | } |
| 204 | |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 205 | void HandleTranslationUnit(ASTContext &Context) override { |
| 206 | const SourceManager &SourceMgr = Context.getSourceManager(); |
| 207 | for (unsigned Offset : SymbolOffsets) { |
| 208 | if (!FindSymbol(Context, SourceMgr, Offset, "")) |
| 209 | return; |
| 210 | } |
| 211 | for (const std::string &QualifiedName : QualifiedNames) { |
| 212 | if (!FindSymbol(Context, SourceMgr, 0, QualifiedName)) |
| 213 | return; |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | ArrayRef<unsigned> SymbolOffsets; |
| 218 | ArrayRef<std::string> QualifiedNames; |
| 219 | std::vector<std::string> &SpellingNames; |
| 220 | std::vector<std::vector<std::string>> &USRList; |
| 221 | bool &ErrorOccurred; |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 222 | }; |
| 223 | |
Kirill Bobyrev | 953a978 | 2016-07-19 07:37:43 +0000 | [diff] [blame] | 224 | std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() { |
Kirill Bobyrev | e5e7e15 | 2016-09-16 08:45:19 +0000 | [diff] [blame] | 225 | return llvm::make_unique<NamedDeclFindingConsumer>( |
| 226 | SymbolOffsets, QualifiedNames, SpellingNames, USRList, ErrorOccurred); |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 227 | } |
| 228 | |
| 229 | } // namespace rename |
| 230 | } // namespace clang |