clang-tools  3.9.0
USRLocFinder.cpp
Go to the documentation of this file.
1 //===--- 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"
23 #include "clang/Lex/Lexer.h"
24 #include "llvm/ADT/SmallVector.h"
25 
26 using namespace llvm;
27 
28 namespace clang {
29 namespace rename {
30 
31 namespace {
32 // \brief This visitor recursively searches for all instances of a USR in a
33 // translation unit and stores them for later usage.
34 class USRLocFindingASTVisitor
35  : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
36 public:
37  explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName)
38  : USR(USR), PrevName(PrevName) {}
39 
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 
49  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 
61  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
62  const ASTContext &Context = ConstructorDecl->getASTContext();
63  for (auto &Initializer : ConstructorDecl->inits()) {
64  if (Initializer->getSourceOrder() == -1) {
65  // Ignore implicit initializers.
66  continue;
67  }
68 
69  if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) {
70  if (getUSRForDecl(FieldDecl) == USR) {
71  // The initializer refers to a field that is to be renamed.
72  SourceLocation Location = Initializer->getSourceLocation();
73  StringRef TokenName = Lexer::getSourceText(
74  CharSourceRange::getTokenRange(Location),
75  Context.getSourceManager(), Context.getLangOpts());
76  if (TokenName == PrevName) {
77  // The token of the source location we find actually has the old
78  // name.
79  LocationsFound.push_back(Initializer->getSourceLocation());
80  }
81  }
82  }
83  }
84 
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  }
89  return true;
90  }
91 
92  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();
97  StringRef LLVM_ATTRIBUTE_UNUSED TokenName = Lexer::getSourceText(
98  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 
114  // 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) {
121  const SourceManager &Manager = Decl->getASTContext().getSourceManager();
122  SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation());
123  LocationsFound.push_back(Location);
124  }
125 
126  return true;
127  }
128 
129  bool VisitMemberExpr(const MemberExpr *Expr) {
130  const auto *Decl = Expr->getFoundDecl().getDecl();
131  if (getUSRForDecl(Decl) == USR) {
132  const SourceManager &Manager = Decl->getASTContext().getSourceManager();
133  SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc());
134  LocationsFound.push_back(Location);
135  }
136  return true;
137  }
138 
139  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 
150  bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr *Expr) {
151  return handleCXXNamedCastExpr(Expr);
152  }
153 
154  bool VisitCXXDynamicCastExpr(clang::CXXDynamicCastExpr *Expr) {
155  return handleCXXNamedCastExpr(Expr);
156  }
157 
158  bool VisitCXXReinterpretCastExpr(clang::CXXReinterpretCastExpr *Expr) {
159  return handleCXXNamedCastExpr(Expr);
160  }
161 
162  bool VisitCXXConstCastExpr(clang::CXXConstCastExpr *Expr) {
163  return handleCXXNamedCastExpr(Expr);
164  }
165 
166  // 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 
174 private:
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 
185  bool handleCXXNamedCastExpr(clang::CXXNamedCastExpr *Expr) {
186  clang::QualType Type = Expr->getType();
187  // See if this a cast of a pointer.
188  const RecordDecl *Decl = Type->getPointeeCXXRecordDecl();
189  if (!Decl) {
190  // See if this is a cast of a reference.
191  Decl = Type->getAsCXXRecordDecl();
192  }
193 
194  if (Decl && getUSRForDecl(Decl) == USR) {
195  SourceLocation Location =
196  Expr->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
197  LocationsFound.push_back(Location);
198  }
199 
200  return true;
201  }
202 
203  // All the locations of the USR were found.
204  const std::string USR;
205  // Old name that is renamed.
206  const std::string PrevName;
207  std::vector<clang::SourceLocation> LocationsFound;
208 };
209 } // namespace
210 
211 std::vector<SourceLocation> getLocationsOfUSR(StringRef USR, StringRef PrevName,
212  Decl *Decl) {
213  USRLocFindingASTVisitor Visitor(USR, PrevName);
214 
215  Visitor.TraverseDecl(Decl);
216  return Visitor.getLocationsFound();
217 }
218 
219 } // namespace rename
220 } // namespace clang
std::string getUSRForDecl(const Decl *Decl)
Definition: USRFinder.cpp:184
const std::string USR
Methods for determining the USR of a symbol at a location in source code.
const std::string PrevName
Provides functionality for finding all instances of a USR in a given AST.
std::vector< clang::SourceLocation > LocationsFound
std::vector< SourceLocation > getLocationsOfUSR(StringRef USR, StringRef PrevName, Decl *Decl)
ClangTidyContext & Context
Definition: ClangTidy.cpp:93