clang-tools  4.0.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/LLVM.h"
22 #include "clang/Basic/SourceLocation.h"
23 #include "clang/Basic/SourceManager.h"
24 #include "clang/Lex/Lexer.h"
25 #include "llvm/ADT/StringRef.h"
26 #include "llvm/Support/Casting.h"
27 #include <cstddef>
28 #include <set>
29 #include <string>
30 #include <vector>
31 
32 using namespace llvm;
33 
34 namespace clang {
35 namespace rename {
36 
37 namespace {
38 
39 // \brief This visitor recursively searches for all instances of a USR in a
40 // translation unit and stores them for later usage.
41 class USRLocFindingASTVisitor
42  : public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
43 public:
44  explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
45  StringRef PrevName,
46  const ASTContext &Context)
47  : USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
48  }
49 
50  // Declaration visitors:
51 
52  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
53  for (const auto *Initializer : ConstructorDecl->inits()) {
54  // Ignore implicit initializers.
55  if (!Initializer->isWritten())
56  continue;
57  if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {
58  if (USRSet.find(getUSRForDecl(FieldDecl)) != USRSet.end())
59  LocationsFound.push_back(Initializer->getSourceLocation());
60  }
61  }
62  return true;
63  }
64 
65  bool VisitNamedDecl(const NamedDecl *Decl) {
66  if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end())
67  checkAndAddLocation(Decl->getLocation());
68  return true;
69  }
70 
71  // Expression visitors:
72 
73  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
74  const NamedDecl *Decl = Expr->getFoundDecl();
75 
76  if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) {
77  const SourceManager &Manager = Decl->getASTContext().getSourceManager();
78  SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation());
79  checkAndAddLocation(Location);
80  }
81 
82  return true;
83  }
84 
85  bool VisitMemberExpr(const MemberExpr *Expr) {
86  const NamedDecl *Decl = Expr->getFoundDecl().getDecl();
87  if (USRSet.find(getUSRForDecl(Decl)) != USRSet.end()) {
88  const SourceManager &Manager = Decl->getASTContext().getSourceManager();
89  SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc());
90  checkAndAddLocation(Location);
91  }
92  return true;
93  }
94 
95  // Other visitors:
96 
97  bool VisitTypeLoc(const TypeLoc Loc) {
98  if (USRSet.find(getUSRForDecl(Loc.getType()->getAsCXXRecordDecl())) !=
99  USRSet.end())
100  checkAndAddLocation(Loc.getBeginLoc());
101  if (const auto *TemplateTypeParm =
102  dyn_cast<TemplateTypeParmType>(Loc.getType())) {
103  if (USRSet.find(getUSRForDecl(TemplateTypeParm->getDecl())) !=
104  USRSet.end())
105  checkAndAddLocation(Loc.getBeginLoc());
106  }
107  return true;
108  }
109 
110  // Non-visitors:
111 
112  // \brief Returns a list of unique locations. Duplicate or overlapping
113  // locations are erroneous and should be reported!
114  const std::vector<clang::SourceLocation> &getLocationsFound() const {
115  return LocationsFound;
116  }
117 
118  // Namespace traversal:
119  void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
120  while (NameLoc) {
121  const NamespaceDecl *Decl =
122  NameLoc.getNestedNameSpecifier()->getAsNamespace();
123  if (Decl && USRSet.find(getUSRForDecl(Decl)) != USRSet.end())
124  checkAndAddLocation(NameLoc.getLocalBeginLoc());
125  NameLoc = NameLoc.getPrefix();
126  }
127  }
128 
129 private:
130  void checkAndAddLocation(SourceLocation Loc) {
131  const SourceLocation BeginLoc = Loc;
132  const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
133  BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
134  StringRef TokenName =
135  Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
136  Context.getSourceManager(), Context.getLangOpts());
137  size_t Offset = TokenName.find(PrevName);
138 
139  // The token of the source location we find actually has the old
140  // name.
141  if (Offset != StringRef::npos)
142  LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset));
143  }
144 
145  const std::set<std::string> USRSet;
146  const std::string PrevName;
147  std::vector<clang::SourceLocation> LocationsFound;
148  const ASTContext &Context;
149 };
150 
151 } // namespace
152 
153 std::vector<SourceLocation>
154 getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName,
155  Decl *Decl) {
156  USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
157  Visitor.TraverseDecl(Decl);
158  NestedNameSpecifierLocFinder Finder(Decl->getASTContext());
159 
160  for (const auto &Location : Finder.getNestedNameSpecifierLocations())
161  Visitor.handleNestedNameSpecifierLoc(Location);
162 
163  return Visitor.getLocationsFound();
164 }
165 
166 } // namespace rename
167 } // namespace clang
SourceLocation Loc
'#' location in the include directive
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:262
std::string getUSRForDecl(const Decl *Decl)
Definition: USRFinder.cpp:201
const ASTContext & Context
const std::set< std::string > USRSet
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 > getLocationsOfUSRs(const std::vector< std::string > &USRs, StringRef PrevName, Decl *Decl)