blob: 5979ecd1d82db3588bc9eeb63f8e1d40745fafab [file] [log] [blame]
Manuel Klimekde237262014-08-20 01:39:05 +00001//===--- tools/extra/clang-rename/USRLocFinder.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
11/// \brief Mehtods for finding all instances of a USR. Our strategy is very
12/// simple; we just compare the USR at every relevant AST node with the one
13/// provided.
14///
15//===----------------------------------------------------------------------===//
16
17#include "USRLocFinder.h"
18#include "USRFinder.h"
19#include "clang/AST/ASTContext.h"
20#include "clang/AST/RecursiveASTVisitor.h"
21#include "clang/Basic/SourceLocation.h"
22#include "clang/Index/USRGeneration.h"
Miklos Vajna1d48e502016-05-13 09:17:32 +000023#include "clang/Lex/Lexer.h"
Manuel Klimekde237262014-08-20 01:39:05 +000024#include "llvm/ADT/SmallVector.h"
25
26using namespace llvm;
27
28namespace clang {
29namespace rename {
30
31namespace {
32// \brief This visitor recursively searches for all instances of a USR in a
33// translation unit and stores them for later usage.
34class USRLocFindingASTVisitor
35 : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
36public:
Benjamin Kramer1afefc02016-07-14 09:46:03 +000037 explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName)
38 : USR(USR), PrevName(PrevName) {}
Manuel Klimekde237262014-08-20 01:39:05 +000039
40 // Declaration visitors:
41
42 bool VisitNamedDecl(const NamedDecl *Decl) {
43 if (getUSRForDecl(Decl) == USR) {
44 LocationsFound.push_back(Decl->getLocation());
45 }
46 return true;
47 }
48
Manuel Klimek13e2c1a2016-05-04 09:45:44 +000049 bool VisitVarDecl(clang::VarDecl *Decl) {
50 clang::QualType Type = Decl->getType();
51 const clang::RecordDecl *RecordDecl = Type->getPointeeCXXRecordDecl();
52 if (RecordDecl) {
53 if (getUSRForDecl(RecordDecl) == USR) {
54 // The declaration refers to a type that is to be renamed.
55 LocationsFound.push_back(Decl->getTypeSpecStartLoc());
56 }
57 }
58 return true;
59 }
60
Miklos Vajna65f088f2016-05-07 14:32:59 +000061 bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
Miklos Vajna1d48e502016-05-13 09:17:32 +000062 const ASTContext &Context = ConstructorDecl->getASTContext();
Benjamin Kramer1afefc02016-07-14 09:46:03 +000063 for (auto &Initializer : ConstructorDecl->inits()) {
Miklos Vajna64776822016-05-11 08:08:07 +000064 if (Initializer->getSourceOrder() == -1) {
65 // Ignore implicit initializers.
66 continue;
67 }
68
Miklos Vajna65f088f2016-05-07 14:32:59 +000069 if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) {
70 if (getUSRForDecl(FieldDecl) == USR) {
71 // The initializer refers to a field that is to be renamed.
Miklos Vajna1d48e502016-05-13 09:17:32 +000072 SourceLocation Location = Initializer->getSourceLocation();
Benjamin Kramer1afefc02016-07-14 09:46:03 +000073 StringRef TokenName = Lexer::getSourceText(
74 CharSourceRange::getTokenRange(Location),
75 Context.getSourceManager(), Context.getLangOpts());
Miklos Vajna1d48e502016-05-13 09:17:32 +000076 if (TokenName == PrevName) {
Benjamin Kramer1afefc02016-07-14 09:46:03 +000077 // The token of the source location we find actually has the old
78 // name.
Miklos Vajna1d48e502016-05-13 09:17:32 +000079 LocationsFound.push_back(Initializer->getSourceLocation());
80 }
Miklos Vajna65f088f2016-05-07 14:32:59 +000081 }
82 }
83 }
Miklos Vajna5a6d2982016-05-18 16:12:48 +000084
85 if (getUSRForDecl(ConstructorDecl) == USR) {
86 // This takes care of the class name part of a non-inline ctor definition.
87 LocationsFound.push_back(ConstructorDecl->getLocStart());
88 }
Miklos Vajna65f088f2016-05-07 14:32:59 +000089 return true;
90 }
91
Miklos Vajna7712bf32016-06-15 18:35:41 +000092 bool VisitCXXDestructorDecl(clang::CXXDestructorDecl *DestructorDecl) {
93 if (getUSRForDecl(DestructorDecl->getParent()) == USR) {
94 // Handles "~Foo" from "Foo::~Foo".
95 SourceLocation Location = DestructorDecl->getLocation();
96 const ASTContext &Context = DestructorDecl->getASTContext();
Artem Belevich0ccbe692016-06-15 23:04:42 +000097 StringRef LLVM_ATTRIBUTE_UNUSED TokenName = Lexer::getSourceText(
Miklos Vajna7712bf32016-06-15 18:35:41 +000098 CharSourceRange::getTokenRange(Location), Context.getSourceManager(),
99 Context.getLangOpts());
100 // 1 is the length of the "~" string that is not to be touched by the
101 // rename.
102 assert(TokenName.startswith("~"));
103 LocationsFound.push_back(Location.getLocWithOffset(1));
104
105 if (DestructorDecl->isThisDeclarationADefinition()) {
106 // Handles "Foo" from "Foo::~Foo".
107 LocationsFound.push_back(DestructorDecl->getLocStart());
108 }
109 }
110
111 return true;
112 }
113
Manuel Klimekde237262014-08-20 01:39:05 +0000114 // Expression visitors:
115
116 bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
117 const auto *Decl = Expr->getFoundDecl();
118
119 checkNestedNameSpecifierLoc(Expr->getQualifierLoc());
120 if (getUSRForDecl(Decl) == USR) {
Miklos Vajna10e25742016-05-24 19:08:53 +0000121 const SourceManager &Manager = Decl->getASTContext().getSourceManager();
122 SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation());
123 LocationsFound.push_back(Location);
Manuel Klimekde237262014-08-20 01:39:05 +0000124 }
125
126 return true;
127 }
128
129 bool VisitMemberExpr(const MemberExpr *Expr) {
130 const auto *Decl = Expr->getFoundDecl().getDecl();
131 if (getUSRForDecl(Decl) == USR) {
Miklos Vajnaed28d412016-05-20 11:43:59 +0000132 const SourceManager &Manager = Decl->getASTContext().getSourceManager();
133 SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc());
134 LocationsFound.push_back(Location);
Manuel Klimekde237262014-08-20 01:39:05 +0000135 }
136 return true;
137 }
138
Miklos Vajna617409f2016-06-02 20:00:22 +0000139 bool VisitCXXConstructExpr(const CXXConstructExpr *Expr) {
140 CXXConstructorDecl *Decl = Expr->getConstructor();
141
142 if (getUSRForDecl(Decl) == USR) {
143 // This takes care of 'new <name>' expressions.
144 LocationsFound.push_back(Expr->getLocation());
145 }
146
147 return true;
148 }
149
Miklos Vajnab54a26d2016-06-06 19:40:12 +0000150 bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr *Expr) {
Miklos Vajna85b7b1c2016-06-08 18:38:23 +0000151 return handleCXXNamedCastExpr(Expr);
152 }
Miklos Vajnab54a26d2016-06-06 19:40:12 +0000153
Miklos Vajna85b7b1c2016-06-08 18:38:23 +0000154 bool VisitCXXDynamicCastExpr(clang::CXXDynamicCastExpr *Expr) {
155 return handleCXXNamedCastExpr(Expr);
Miklos Vajnab54a26d2016-06-06 19:40:12 +0000156 }
157
Miklos Vajna6ff8f252016-06-13 18:50:45 +0000158 bool VisitCXXReinterpretCastExpr(clang::CXXReinterpretCastExpr *Expr) {
159 return handleCXXNamedCastExpr(Expr);
160 }
161
162 bool VisitCXXConstCastExpr(clang::CXXConstCastExpr *Expr) {
163 return handleCXXNamedCastExpr(Expr);
164 }
165
Manuel Klimekde237262014-08-20 01:39:05 +0000166 // Non-visitors:
167
168 // \brief Returns a list of unique locations. Duplicate or overlapping
169 // locations are erroneous and should be reported!
170 const std::vector<clang::SourceLocation> &getLocationsFound() const {
171 return LocationsFound;
172 }
173
174private:
175 // Namespace traversal:
176 void checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
177 while (NameLoc) {
178 const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
179 if (Decl && getUSRForDecl(Decl) == USR)
180 LocationsFound.push_back(NameLoc.getLocalBeginLoc());
181 NameLoc = NameLoc.getPrefix();
182 }
183 }
184
Miklos Vajna85b7b1c2016-06-08 18:38:23 +0000185 bool handleCXXNamedCastExpr(clang::CXXNamedCastExpr *Expr) {
186 clang::QualType Type = Expr->getType();
187 // See if this a cast of a pointer.
Benjamin Kramer1afefc02016-07-14 09:46:03 +0000188 const RecordDecl *Decl = Type->getPointeeCXXRecordDecl();
Miklos Vajna85b7b1c2016-06-08 18:38:23 +0000189 if (!Decl) {
190 // See if this is a cast of a reference.
191 Decl = Type->getAsCXXRecordDecl();
192 }
193
194 if (Decl && getUSRForDecl(Decl) == USR) {
Benjamin Kramer1afefc02016-07-14 09:46:03 +0000195 SourceLocation Location =
196 Expr->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
Miklos Vajna85b7b1c2016-06-08 18:38:23 +0000197 LocationsFound.push_back(Location);
198 }
199
200 return true;
201 }
202
Manuel Klimekde237262014-08-20 01:39:05 +0000203 // All the locations of the USR were found.
Miklos Vajnaa7445f12016-05-17 18:17:16 +0000204 const std::string USR;
Miklos Vajna1d48e502016-05-13 09:17:32 +0000205 // Old name that is renamed.
Miklos Vajnaa7445f12016-05-17 18:17:16 +0000206 const std::string PrevName;
Manuel Klimekde237262014-08-20 01:39:05 +0000207 std::vector<clang::SourceLocation> LocationsFound;
208};
209} // namespace
210
Benjamin Kramer1afefc02016-07-14 09:46:03 +0000211std::vector<SourceLocation> getLocationsOfUSR(StringRef USR, StringRef PrevName,
Manuel Klimekde237262014-08-20 01:39:05 +0000212 Decl *Decl) {
Kirill Bobyrev32db7692016-07-15 11:29:16 +0000213 USRLocFindingASTVisitor Visitor(USR, PrevName);
Manuel Klimekde237262014-08-20 01:39:05 +0000214
Kirill Bobyrev32db7692016-07-15 11:29:16 +0000215 Visitor.TraverseDecl(Decl);
216 return Visitor.getLocationsFound();
Manuel Klimekde237262014-08-20 01:39:05 +0000217}
218
219} // namespace rename
220} // namespace clang