blob: 6915e4292da915c422e307d2894c4bf8c0eff6f1 [file] [log] [blame]
Manuel Klimekde237262014-08-20 01:39:05 +00001//===--- 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 Bobyrev953a9782016-07-19 07:37:43 +000011/// \brief Provides an action to find USR for the symbol at <offset>, as well as
12/// all additional USRs.
Manuel Klimekde237262014-08-20 01:39:05 +000013///
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 Bobyrev953a9782016-07-19 07:37:43 +000021#include "clang/AST/Decl.h"
22#include "clang/AST/RecursiveASTVisitor.h"
Manuel Klimekde237262014-08-20 01:39:05 +000023#include "clang/Basic/FileManager.h"
24#include "clang/Frontend/CompilerInstance.h"
25#include "clang/Frontend/FrontendAction.h"
Manuel Klimekde237262014-08-20 01:39:05 +000026#include "clang/Lex/Lexer.h"
Chandler Carruth3cbd71c2015-01-14 11:24:38 +000027#include "clang/Lex/Preprocessor.h"
Manuel Klimekde237262014-08-20 01:39:05 +000028#include "clang/Tooling/CommonOptionsParser.h"
29#include "clang/Tooling/Refactoring.h"
30#include "clang/Tooling/Tooling.h"
Kirill Bobyreve5e7e152016-09-16 08:45:19 +000031
Kirill Bobyrev953a9782016-07-19 07:37:43 +000032#include <algorithm>
Kirill Bobyrev953a9782016-07-19 07:37:43 +000033#include <set>
Kirill Bobyrev81009402016-08-04 09:23:30 +000034#include <string>
Manuel Klimekde237262014-08-20 01:39:05 +000035#include <vector>
36
37using namespace llvm;
38
39namespace clang {
40namespace rename {
41
Kirill Bobyrev953a9782016-07-19 07:37:43 +000042namespace {
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 Bobyrevd6ab7d42016-08-03 23:00:32 +000047class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> {
Kirill Bobyrev953a9782016-07-19 07:37:43 +000048public:
Kirill Bobyreve5e7e152016-09-16 08:45:19 +000049 AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
50 : FoundDecl(FoundDecl), Context(Context) {}
Manuel Klimekde237262014-08-20 01:39:05 +000051
Kirill Bobyreve5e7e152016-09-16 08:45:19 +000052 std::vector<std::string> Find() {
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000053 // Fill OverriddenMethods and PartialSpecs storages.
54 TraverseDecl(Context.getTranslationUnitDecl());
Kirill Bobyrev91053e02016-08-01 17:15:57 +000055 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000056 addUSRsOfOverridenFunctions(MethodDecl);
57 for (const auto &OverriddenMethod : OverriddenMethods) {
Kirill Bobyrev87697782016-09-04 22:50:41 +000058 if (checkIfOverriddenFunctionAscends(OverriddenMethod))
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000059 USRSet.insert(getUSRForDecl(OverriddenMethod));
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000060 }
61 } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) {
62 handleCXXRecordDecl(RecordDecl);
63 } else if (const auto *TemplateDecl =
Miklos Vajna0c07f0c2016-08-04 07:43:29 +000064 dyn_cast<ClassTemplateDecl>(FoundDecl)) {
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000065 handleClassTemplateDecl(TemplateDecl);
66 } else {
67 USRSet.insert(getUSRForDecl(FoundDecl));
Kirill Bobyrev91053e02016-08-01 17:15:57 +000068 }
Kirill Bobyreve5e7e152016-09-16 08:45:19 +000069 return std::vector<std::string>(USRSet.begin(), USRSet.end());
Kirill Bobyrev953a9782016-07-19 07:37:43 +000070 }
Manuel Klimekde237262014-08-20 01:39:05 +000071
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000072 bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {
Kirill Bobyrev87697782016-09-04 22:50:41 +000073 if (MethodDecl->isVirtual())
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000074 OverriddenMethods.push_back(MethodDecl);
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000075 return true;
Kirill Bobyrev953a9782016-07-19 07:37:43 +000076 }
Manuel Klimekde237262014-08-20 01:39:05 +000077
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000078 bool VisitClassTemplatePartialSpecializationDecl(
79 const ClassTemplatePartialSpecializationDecl *PartialSpec) {
80 PartialSpecs.push_back(PartialSpec);
81 return true;
82 }
83
84private:
85 void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
86 RecordDecl = RecordDecl->getDefinition();
Miklos Vajna0c07f0c2016-08-04 07:43:29 +000087 if (const auto *ClassTemplateSpecDecl =
Kirill Bobyrev87697782016-09-04 22:50:41 +000088 dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000089 handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate());
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000090 addUSRsOfCtorDtors(RecordDecl);
91 }
92
93 void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {
Kirill Bobyrev87697782016-09-04 22:50:41 +000094 for (const auto *Specialization : TemplateDecl->specializations())
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000095 addUSRsOfCtorDtors(Specialization);
Kirill Bobyrev87697782016-09-04 22:50:41 +000096
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000097 for (const auto *PartialSpec : PartialSpecs) {
Kirill Bobyrev87697782016-09-04 22:50:41 +000098 if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +000099 addUSRsOfCtorDtors(PartialSpec);
Kirill Bobyrev953a9782016-07-19 07:37:43 +0000100 }
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +0000101 addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
Kirill Bobyrev953a9782016-07-19 07:37:43 +0000102 }
Manuel Klimekde237262014-08-20 01:39:05 +0000103
Kirill Bobyrev91053e02016-08-01 17:15:57 +0000104 void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) {
105 RecordDecl = RecordDecl->getDefinition();
Kirill Bobyrev87697782016-09-04 22:50:41 +0000106
Haojian Wu74f823a2017-04-04 09:30:06 +0000107 // Skip if the CXXRecordDecl doesn't have definition.
108 if (!RecordDecl)
109 return;
110
Kirill Bobyrev87697782016-09-04 22:50:41 +0000111 for (const auto *CtorDecl : RecordDecl->ctors())
Kirill Bobyrev91053e02016-08-01 17:15:57 +0000112 USRSet.insert(getUSRForDecl(CtorDecl));
Kirill Bobyrev87697782016-09-04 22:50:41 +0000113
Kirill Bobyrev91053e02016-08-01 17:15:57 +0000114 USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +0000115 USRSet.insert(getUSRForDecl(RecordDecl));
Kirill Bobyrev91053e02016-08-01 17:15:57 +0000116 }
117
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +0000118 void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) {
Kirill Bobyrev91053e02016-08-01 17:15:57 +0000119 USRSet.insert(getUSRForDecl(MethodDecl));
Kirill Bobyrev87697782016-09-04 22:50:41 +0000120 // Recursively visit each OverridenMethod.
121 for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +0000122 addUSRsOfOverridenFunctions(OverriddenMethod);
Kirill Bobyrev953a9782016-07-19 07:37:43 +0000123 }
124
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +0000125 bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) {
Kirill Bobyrev6b7d8c22016-08-15 23:20:05 +0000126 for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) {
Kirill Bobyrev87697782016-09-04 22:50:41 +0000127 if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end())
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +0000128 return true;
Kirill Bobyrevd6ab7d42016-08-03 23:00:32 +0000129 return checkIfOverriddenFunctionAscends(OverriddenMethod);
130 }
131 return false;
132 }
133
Kirill Bobyrev953a9782016-07-19 07:37:43 +0000134 const Decl *FoundDecl;
135 ASTContext &Context;
Kirill Bobyrev953a9782016-07-19 07:37:43 +0000136 std::set<std::string> USRSet;
Miklos Vajna0c07f0c2016-08-04 07:43:29 +0000137 std::vector<const CXXMethodDecl *> OverriddenMethods;
138 std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs;
Kirill Bobyrev953a9782016-07-19 07:37:43 +0000139};
140} // namespace
Manuel Klimekde237262014-08-20 01:39:05 +0000141
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000142class NamedDeclFindingConsumer : public ASTConsumer {
143public:
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
153private:
154 bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
155 unsigned SymbolOffset, const std::string &QualifiedName) {
156 DiagnosticsEngine &Engine = Context.getDiagnostics();
Benjamin Kramer66039d32016-11-23 13:10:07 +0000157 const FileID MainFileID = SourceMgr.getMainFileID();
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000158
Benjamin Kramer66039d32016-11-23 13:10:07 +0000159 if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000160 ErrorOccurred = true;
161 unsigned InvalidOffset = Engine.getCustomDiagID(
162 DiagnosticsEngine::Error,
163 "SourceLocation in file %0 at offset %1 is invalid");
Benjamin Kramer66039d32016-11-23 13:10:07 +0000164 Engine.Report(SourceLocation(), InvalidOffset)
165 << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset;
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000166 return false;
Kirill Bobyrevc2ed91f2016-09-14 13:00:36 +0000167 }
168
Benjamin Kramer66039d32016-11-23 13:10:07 +0000169 const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID)
170 .getLocWithOffset(SymbolOffset);
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000171 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 Bobyrev87697782016-09-04 22:50:41 +0000194 if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
Manuel Klimekde237262014-08-20 01:39:05 +0000195 FoundDecl = CtorDecl->getParent();
Kirill Bobyrev87697782016-09-04 22:50:41 +0000196 else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
Manuel Klimekde237262014-08-20 01:39:05 +0000197 FoundDecl = DtorDecl->getParent();
Kirill Bobyrev87697782016-09-04 22:50:41 +0000198
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000199 SpellingNames.push_back(FoundDecl->getNameAsString());
200 AdditionalUSRFinder Finder(FoundDecl, Context);
201 USRList.push_back(Finder.Find());
202 return true;
Manuel Klimekde237262014-08-20 01:39:05 +0000203 }
204
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000205 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 Klimekde237262014-08-20 01:39:05 +0000222};
223
Kirill Bobyrev953a9782016-07-19 07:37:43 +0000224std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
Kirill Bobyreve5e7e152016-09-16 08:45:19 +0000225 return llvm::make_unique<NamedDeclFindingConsumer>(
226 SymbolOffsets, QualifiedNames, SpellingNames, USRList, ErrorOccurred);
Manuel Klimekde237262014-08-20 01:39:05 +0000227}
228
229} // namespace rename
230} // namespace clang