2014-08-20 09:39:05 +08:00
|
|
|
//===--- 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
|
2016-07-19 15:37:43 +08:00
|
|
|
/// \brief Provides an action to find USR for the symbol at <offset>, as well as
|
|
|
|
/// all additional USRs.
|
2014-08-20 09:39:05 +08:00
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "USRFindingAction.h"
|
|
|
|
#include "USRFinder.h"
|
|
|
|
#include "clang/AST/AST.h"
|
|
|
|
#include "clang/AST/ASTConsumer.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2016-07-19 15:37:43 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/AST/RecursiveASTVisitor.h"
|
|
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
2014-08-20 09:39:05 +08:00
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
|
|
#include "clang/Frontend/FrontendAction.h"
|
|
|
|
#include "clang/Lex/Lexer.h"
|
2015-01-14 19:24:38 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2014-08-20 09:39:05 +08:00
|
|
|
#include "clang/Tooling/CommonOptionsParser.h"
|
|
|
|
#include "clang/Tooling/Refactoring.h"
|
|
|
|
#include "clang/Tooling/Tooling.h"
|
2016-07-19 15:37:43 +08:00
|
|
|
#include <algorithm>
|
2014-08-20 09:39:05 +08:00
|
|
|
#include <string>
|
2016-07-19 15:37:43 +08:00
|
|
|
#include <set>
|
2014-08-20 09:39:05 +08:00
|
|
|
#include <vector>
|
|
|
|
|
2016-07-19 15:37:43 +08:00
|
|
|
|
2014-08-20 09:39:05 +08:00
|
|
|
using namespace llvm;
|
2016-07-19 15:37:43 +08:00
|
|
|
using namespace clang::ast_matchers;
|
2014-08-20 09:39:05 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace rename {
|
|
|
|
|
2016-07-19 15:37:43 +08:00
|
|
|
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
|
2014-08-20 09:39:05 +08:00
|
|
|
|
|
|
|
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.
|
2016-07-19 15:37:43 +08:00
|
|
|
const auto Point = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID())
|
|
|
|
.getLocWithOffset(SymbolOffset);
|
2014-08-20 09:39:05 +08:00
|
|
|
if (!Point.isValid())
|
|
|
|
return;
|
2016-06-22 03:48:57 +08:00
|
|
|
const NamedDecl *FoundDecl = nullptr;
|
|
|
|
if (OldName.empty()) {
|
|
|
|
FoundDecl = getNamedDeclAt(Context, Point);
|
|
|
|
} else {
|
|
|
|
FoundDecl = getNamedDeclFor(Context, OldName);
|
|
|
|
}
|
2014-08-20 09:39:05 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-19 15:37:43 +08:00
|
|
|
// 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)) {
|
2014-08-20 09:39:05 +08:00
|
|
|
FoundDecl = CtorDecl->getParent();
|
2016-07-19 15:37:43 +08:00
|
|
|
} else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl)) {
|
2014-08-20 09:39:05 +08:00
|
|
|
FoundDecl = DtorDecl->getParent();
|
2016-07-19 15:37:43 +08:00
|
|
|
}
|
2014-08-20 09:39:05 +08:00
|
|
|
*SpellingName = FoundDecl->getNameAsString();
|
2016-07-19 15:37:43 +08:00
|
|
|
|
|
|
|
AdditionalUSRFinder Finder(FoundDecl, Context, USRs);
|
|
|
|
Finder.Find();
|
2014-08-20 09:39:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned SymbolOffset;
|
2016-06-22 03:48:57 +08:00
|
|
|
std::string OldName;
|
2014-08-20 09:39:05 +08:00
|
|
|
std::string *SpellingName;
|
|
|
|
std::vector<std::string> *USRs;
|
|
|
|
};
|
|
|
|
|
2016-07-19 15:37:43 +08:00
|
|
|
std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
|
2014-08-20 09:39:05 +08:00
|
|
|
std::unique_ptr<NamedDeclFindingConsumer> Consumer(
|
|
|
|
new NamedDeclFindingConsumer);
|
|
|
|
SpellingName = "";
|
|
|
|
Consumer->SymbolOffset = SymbolOffset;
|
2016-06-22 03:48:57 +08:00
|
|
|
Consumer->OldName = OldName;
|
2014-08-20 09:39:05 +08:00
|
|
|
Consumer->USRs = &USRs;
|
|
|
|
Consumer->SpellingName = &SpellingName;
|
|
|
|
return std::move(Consumer);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace rename
|
|
|
|
} // namespace clang
|