blob: be110f152763d792b5506520b21faaeb78484637 [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:
Miklos Vajna1d48e502016-05-13 09:17:32 +000037 explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName) : USR(USR), PrevName(PrevName) {
Manuel Klimekde237262014-08-20 01:39:05 +000038 }
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
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();
Miklos Vajna65f088f2016-05-07 14:32:59 +000063 for (clang::CXXConstructorDecl::init_const_iterator it = ConstructorDecl->init_begin(); it != ConstructorDecl->init_end(); ++it) {
64 const clang::CXXCtorInitializer* Initializer = *it;
Miklos Vajna64776822016-05-11 08:08:07 +000065 if (Initializer->getSourceOrder() == -1) {
66 // Ignore implicit initializers.
67 continue;
68 }
69
Miklos Vajna65f088f2016-05-07 14:32:59 +000070 if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) {
71 if (getUSRForDecl(FieldDecl) == USR) {
72 // The initializer refers to a field that is to be renamed.
Miklos Vajna1d48e502016-05-13 09:17:32 +000073 SourceLocation Location = Initializer->getSourceLocation();
74 StringRef TokenName = Lexer::getSourceText(CharSourceRange::getTokenRange(Location), Context.getSourceManager(), Context.getLangOpts());
75 if (TokenName == PrevName) {
76 // The token of the source location we find actually has the old name.
77 LocationsFound.push_back(Initializer->getSourceLocation());
78 }
Miklos Vajna65f088f2016-05-07 14:32:59 +000079 }
80 }
81 }
Miklos Vajna5a6d2982016-05-18 16:12:48 +000082
83 if (getUSRForDecl(ConstructorDecl) == USR) {
84 // This takes care of the class name part of a non-inline ctor definition.
85 LocationsFound.push_back(ConstructorDecl->getLocStart());
86 }
Miklos Vajna65f088f2016-05-07 14:32:59 +000087 return true;
88 }
89
Manuel Klimekde237262014-08-20 01:39:05 +000090 // Expression visitors:
91
92 bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
93 const auto *Decl = Expr->getFoundDecl();
94
95 checkNestedNameSpecifierLoc(Expr->getQualifierLoc());
96 if (getUSRForDecl(Decl) == USR) {
Miklos Vajna10e25742016-05-24 19:08:53 +000097 const SourceManager &Manager = Decl->getASTContext().getSourceManager();
98 SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation());
99 LocationsFound.push_back(Location);
Manuel Klimekde237262014-08-20 01:39:05 +0000100 }
101
102 return true;
103 }
104
105 bool VisitMemberExpr(const MemberExpr *Expr) {
106 const auto *Decl = Expr->getFoundDecl().getDecl();
107 if (getUSRForDecl(Decl) == USR) {
Miklos Vajnaed28d412016-05-20 11:43:59 +0000108 const SourceManager &Manager = Decl->getASTContext().getSourceManager();
109 SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc());
110 LocationsFound.push_back(Location);
Manuel Klimekde237262014-08-20 01:39:05 +0000111 }
112 return true;
113 }
114
Miklos Vajna617409f2016-06-02 20:00:22 +0000115 bool VisitCXXConstructExpr(const CXXConstructExpr *Expr) {
116 CXXConstructorDecl *Decl = Expr->getConstructor();
117
118 if (getUSRForDecl(Decl) == USR) {
119 // This takes care of 'new <name>' expressions.
120 LocationsFound.push_back(Expr->getLocation());
121 }
122
123 return true;
124 }
125
Miklos Vajnab54a26d2016-06-06 19:40:12 +0000126 bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr *Expr) {
127 clang::QualType Type = Expr->getType();
128 // See if this a cast of a pointer.
129 const RecordDecl* Decl = Type->getPointeeCXXRecordDecl();
130 if (!Decl) {
131 // See if this is a cast of a reference.
132 Decl = Type->getAsCXXRecordDecl();
133 }
134
135 if (Decl && getUSRForDecl(Decl) == USR) {
136 SourceLocation Location = Expr->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
137 LocationsFound.push_back(Location);
138 }
139
140 return true;
141 }
142
Manuel Klimekde237262014-08-20 01:39:05 +0000143 // Non-visitors:
144
145 // \brief Returns a list of unique locations. Duplicate or overlapping
146 // locations are erroneous and should be reported!
147 const std::vector<clang::SourceLocation> &getLocationsFound() const {
148 return LocationsFound;
149 }
150
151private:
152 // Namespace traversal:
153 void checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
154 while (NameLoc) {
155 const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
156 if (Decl && getUSRForDecl(Decl) == USR)
157 LocationsFound.push_back(NameLoc.getLocalBeginLoc());
158 NameLoc = NameLoc.getPrefix();
159 }
160 }
161
162 // All the locations of the USR were found.
Miklos Vajnaa7445f12016-05-17 18:17:16 +0000163 const std::string USR;
Miklos Vajna1d48e502016-05-13 09:17:32 +0000164 // Old name that is renamed.
Miklos Vajnaa7445f12016-05-17 18:17:16 +0000165 const std::string PrevName;
Manuel Klimekde237262014-08-20 01:39:05 +0000166 std::vector<clang::SourceLocation> LocationsFound;
167};
168} // namespace
169
Miklos Vajna1d48e502016-05-13 09:17:32 +0000170std::vector<SourceLocation> getLocationsOfUSR(StringRef USR,
171 StringRef PrevName,
Manuel Klimekde237262014-08-20 01:39:05 +0000172 Decl *Decl) {
Miklos Vajna1d48e502016-05-13 09:17:32 +0000173 USRLocFindingASTVisitor visitor(USR, PrevName);
Manuel Klimekde237262014-08-20 01:39:05 +0000174
175 visitor.TraverseDecl(Decl);
176 return visitor.getLocationsFound();
177}
178
179} // namespace rename
180} // namespace clang