1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
//===--- tools/extra/clang-rename/USRFindingAction.cpp - Clang rename tool ===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Provides an action to find USR for the symbol at <offset>, as well as
/// all additional USRs.
///
//===----------------------------------------------------------------------===//
#include "USRFindingAction.h"
#include "USRFinder.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include <algorithm>
#include <string>
#include <set>
#include <vector>
using namespace llvm;
using namespace clang::ast_matchers;
namespace clang {
namespace rename {
namespace {
// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to
// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given
// Decl refers to class and adds USRs of all overridden methods if Decl refers
// to virtual method.
//
// FIXME: It's better to match ctors/dtors via typeLoc's instead of adding
// their USRs to the storage, because we can also match CXXConversionDecl's by
// typeLoc and we won't have to "manually" handle them here.
class AdditionalUSRFinder : public MatchFinder::MatchCallback {
public:
explicit AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context,
std::vector<std::string> *USRs)
: FoundDecl(FoundDecl), Context(Context), USRs(USRs), USRSet(), Finder() {}
void Find() {
USRSet.insert(getUSRForDecl(FoundDecl));
addUSRsFromOverrideSetsAndCtorDtors();
addMatchers();
Finder.matchAST(Context);
USRs->insert(USRs->end(), USRSet.begin(), USRSet.end());
}
private:
void addMatchers() {
const auto CXXMethodDeclMatcher =
cxxMethodDecl(isVirtual()).bind("cxxMethodDecl");
Finder.addMatcher(CXXMethodDeclMatcher, this);
}
// FIXME: Implement hasOverriddenMethod and matchesUSR matchers to make
// lookups more efficient.
virtual void run(const MatchFinder::MatchResult &Result) {
const auto *VirtualMethod =
Result.Nodes.getNodeAs<CXXMethodDecl>("cxxMethodDecl");
bool Found = false;
for (const auto &OverriddenMethod : VirtualMethod->overridden_methods()) {
if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) {
Found = true;
}
}
if (Found) {
USRSet.insert(getUSRForDecl(VirtualMethod));
}
}
void addUSRsFromOverrideSetsAndCtorDtors() {
// If D is CXXRecordDecl we should add all USRs of its constructors.
if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) {
// Ignore destructors. Find the declaration of and explicit calls to a
// destructor through TagTypeLoc (and it is better for the purpose of
// renaming).
//
// For example, in the following code segment,
// 1 class C {
// 2 ~C();
// 3 };
//
// At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc
// starting from 'C'.
RecordDecl = RecordDecl->getDefinition();
// Iterate over all the constructors and add their USRs.
for (const auto *CtorDecl : RecordDecl->ctors()) {
USRSet.insert(getUSRForDecl(CtorDecl));
}
}
// If D is CXXMethodDecl we should add all USRs of its overriden methods.
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
for (auto &OverriddenMethod : MethodDecl->overridden_methods()) {
USRSet.insert(getUSRForDecl(OverriddenMethod));
}
}
}
const Decl *FoundDecl;
ASTContext &Context;
std::vector<std::string> *USRs;
std::set<std::string> USRSet;
MatchFinder Finder;
};
} // namespace
struct NamedDeclFindingConsumer : public ASTConsumer {
void HandleTranslationUnit(ASTContext &Context) override {
const auto &SourceMgr = Context.getSourceManager();
// The file we look for the USR in will always be the main source file.
const auto Point = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID())
.getLocWithOffset(SymbolOffset);
if (!Point.isValid())
return;
const NamedDecl *FoundDecl = nullptr;
if (OldName.empty()) {
FoundDecl = getNamedDeclAt(Context, Point);
} else {
FoundDecl = getNamedDeclFor(Context, OldName);
}
if (FoundDecl == nullptr) {
FullSourceLoc FullLoc(Point, SourceMgr);
errs() << "clang-rename: could not find symbol at "
<< SourceMgr.getFilename(Point) << ":"
<< FullLoc.getSpellingLineNumber() << ":"
<< FullLoc.getSpellingColumnNumber() << " (offset " << SymbolOffset
<< ").\n";
return;
}
// If FoundDecl is a constructor or destructor, we want to instead take the
// Decl of the corresponding class.
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl)) {
FoundDecl = CtorDecl->getParent();
} else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl)) {
FoundDecl = DtorDecl->getParent();
}
*SpellingName = FoundDecl->getNameAsString();
AdditionalUSRFinder Finder(FoundDecl, Context, USRs);
Finder.Find();
}
unsigned SymbolOffset;
std::string OldName;
std::string *SpellingName;
std::vector<std::string> *USRs;
};
std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
std::unique_ptr<NamedDeclFindingConsumer> Consumer(
new NamedDeclFindingConsumer);
SpellingName = "";
Consumer->SymbolOffset = SymbolOffset;
Consumer->OldName = OldName;
Consumer->USRs = &USRs;
Consumer->SpellingName = &SpellingName;
return std::move(Consumer);
}
} // namespace rename
} // namespace clang
|