forked from OSchip/llvm-project
[clang-rename] introduce better symbol finding
This patch introduces: * TypeLoc visiting, which helps a lot in renaming types * NestedNameSpecifierLoc visiting (through getting them via ASTMatcher at the moment, though, because RecursiveASTVisitor<T>::VisitNestedNameSpecifierLoc isn't implemented), which helps to treat nested names correctly * better code formatting and refactoring * bunch of tests Reviewers: alexfh Differential revision: https://reviews.llvm.org/D22465 llvm-svn: 276414
This commit is contained in:
parent
bd7aa358f0
commit
a3432fa91c
|
@ -57,19 +57,16 @@ public:
|
|||
}
|
||||
|
||||
auto PrevNameLen = PrevName.length();
|
||||
if (PrintLocations)
|
||||
for (const auto &Loc : RenamingCandidates) {
|
||||
for (const auto &Loc : RenamingCandidates) {
|
||||
if (PrintLocations) {
|
||||
FullSourceLoc FullLoc(Loc, SourceMgr);
|
||||
errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc)
|
||||
<< ":" << FullLoc.getSpellingLineNumber() << ":"
|
||||
<< FullLoc.getSpellingColumnNumber() << "\n";
|
||||
Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen,
|
||||
NewName));
|
||||
}
|
||||
else
|
||||
for (const auto &Loc : RenamingCandidates)
|
||||
Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen,
|
||||
NewName));
|
||||
Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen,
|
||||
NewName));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -35,18 +35,15 @@ public:
|
|||
// \brief Finds the NamedDecl at a point in the source.
|
||||
// \param Point the location in the source to search for the NamedDecl.
|
||||
explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr,
|
||||
const SourceLocation Point)
|
||||
: Result(nullptr), SourceMgr(SourceMgr),
|
||||
Point(Point) {
|
||||
}
|
||||
const SourceLocation Point,
|
||||
const ASTContext *Context)
|
||||
: Result(nullptr), SourceMgr(SourceMgr), Point(Point), Context(Context) {}
|
||||
|
||||
// \brief Finds the NamedDecl for a name in the source.
|
||||
// \param Name the fully qualified name.
|
||||
explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr,
|
||||
const std::string &Name)
|
||||
: Result(nullptr), SourceMgr(SourceMgr),
|
||||
Name(Name) {
|
||||
}
|
||||
: Result(nullptr), SourceMgr(SourceMgr), Name(Name) {}
|
||||
|
||||
// Declaration visitors:
|
||||
|
||||
|
@ -62,10 +59,6 @@ public:
|
|||
// Expression visitors:
|
||||
|
||||
bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
|
||||
// Check the namespace specifier first.
|
||||
if (!checkNestedNameSpecifierLoc(Expr->getQualifierLoc()))
|
||||
return false;
|
||||
|
||||
const auto *Decl = Expr->getFoundDecl();
|
||||
return setResult(Decl, Expr->getLocation(),
|
||||
Decl->getNameAsString().length());
|
||||
|
@ -77,26 +70,33 @@ public:
|
|||
Decl->getNameAsString().length());
|
||||
}
|
||||
|
||||
// Other visitors:
|
||||
|
||||
bool VisitTypeLoc(const TypeLoc Loc) {
|
||||
const auto TypeBeginLoc = Loc.getBeginLoc();
|
||||
const auto TypeEndLoc = Lexer::getLocForEndOfToken(
|
||||
TypeBeginLoc, 0, SourceMgr, Context->getLangOpts());
|
||||
return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc,
|
||||
TypeEndLoc);
|
||||
}
|
||||
|
||||
// Other:
|
||||
|
||||
const NamedDecl *getNamedDecl() {
|
||||
return Result;
|
||||
const NamedDecl *getNamedDecl() { return Result; }
|
||||
|
||||
// \brief Determines if a namespace qualifier contains the point.
|
||||
// \returns false on success and sets Result.
|
||||
void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
|
||||
while (NameLoc) {
|
||||
const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
|
||||
if (Decl) {
|
||||
setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc());
|
||||
}
|
||||
NameLoc = NameLoc.getPrefix();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// \brief Determines if a namespace qualifier contains the point.
|
||||
// \returns false on success and sets Result.
|
||||
bool checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
|
||||
while (NameLoc) {
|
||||
const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
|
||||
if (Decl && !setResult(Decl, NameLoc.getLocalBeginLoc(),
|
||||
Decl->getNameAsString().length()))
|
||||
return false;
|
||||
NameLoc = NameLoc.getPrefix();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// \brief Sets Result to Decl if the Point is within Start and End.
|
||||
// \returns false on success.
|
||||
bool setResult(const NamedDecl *Decl, SourceLocation Start,
|
||||
|
@ -119,8 +119,7 @@ private:
|
|||
|
||||
// \brief Sets Result to Decl if Point is within Loc and Loc + Offset.
|
||||
// \returns false on success.
|
||||
bool setResult(const NamedDecl *Decl, SourceLocation Loc,
|
||||
unsigned Offset) {
|
||||
bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) {
|
||||
// FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc).
|
||||
return Offset == 0 ||
|
||||
setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));
|
||||
|
@ -138,6 +137,7 @@ private:
|
|||
const SourceManager &SourceMgr;
|
||||
const SourceLocation Point; // The location to find the NamedDecl.
|
||||
const std::string Name;
|
||||
const ASTContext *Context;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -146,7 +146,7 @@ const NamedDecl *getNamedDeclAt(const ASTContext &Context,
|
|||
const auto &SourceMgr = Context.getSourceManager();
|
||||
const auto SearchFile = SourceMgr.getFilename(Point);
|
||||
|
||||
NamedDeclFindingASTVisitor Visitor(SourceMgr, Point);
|
||||
NamedDeclFindingASTVisitor Visitor(SourceMgr, Point, &Context);
|
||||
|
||||
// We only want to search the decls that exist in the same file as the point.
|
||||
auto Decls = Context.getTranslationUnitDecl()->decls();
|
||||
|
@ -156,29 +156,24 @@ const NamedDecl *getNamedDeclAt(const ASTContext &Context,
|
|||
// FIXME: Add test.
|
||||
if (FileName == SearchFile) {
|
||||
Visitor.TraverseDecl(CurrDecl);
|
||||
if (const NamedDecl *Result = Visitor.getNamedDecl()) {
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context));
|
||||
for (const auto &Location : Finder.getNestedNameSpecifierLocations()) {
|
||||
Visitor.handleNestedNameSpecifierLoc(Location);
|
||||
}
|
||||
|
||||
return Visitor.getNamedDecl();
|
||||
}
|
||||
|
||||
const NamedDecl *getNamedDeclFor(const ASTContext &Context,
|
||||
const std::string &Name) {
|
||||
const auto &SourceMgr = Context.getSourceManager();
|
||||
NamedDeclFindingASTVisitor Visitor(SourceMgr, Name);
|
||||
auto Decls = Context.getTranslationUnitDecl()->decls();
|
||||
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
|
||||
|
||||
for (auto &CurrDecl : Decls) {
|
||||
Visitor.TraverseDecl(CurrDecl);
|
||||
if (const NamedDecl *Result = Visitor.getNamedDecl()) {
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return Visitor.getNamedDecl();
|
||||
}
|
||||
|
||||
std::string getUSRForDecl(const Decl *Decl) {
|
||||
|
|
|
@ -15,8 +15,14 @@
|
|||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H
|
||||
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include <string>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
|
@ -39,6 +45,36 @@ const NamedDecl *getNamedDeclFor(const ASTContext &Context,
|
|||
// Converts a Decl into a USR.
|
||||
std::string getUSRForDecl(const Decl *Decl);
|
||||
|
||||
// FIXME: Implement RecursiveASTVisitor<T>::VisitNestedNameSpecifier instead.
|
||||
class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
explicit NestedNameSpecifierLocFinder(ASTContext &Context)
|
||||
: Context(Context) {}
|
||||
|
||||
std::vector<NestedNameSpecifierLoc> getNestedNameSpecifierLocations() {
|
||||
addMatchers();
|
||||
Finder.matchAST(Context);
|
||||
return Locations;
|
||||
}
|
||||
|
||||
private:
|
||||
void addMatchers() {
|
||||
const auto NestedNameSpecifierLocMatcher =
|
||||
nestedNameSpecifierLoc().bind("nestedNameSpecifierLoc");
|
||||
Finder.addMatcher(NestedNameSpecifierLocMatcher, this);
|
||||
}
|
||||
|
||||
virtual void run(const MatchFinder::MatchResult &Result) {
|
||||
const auto *NNS =
|
||||
Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("nestedNameSpecifierLoc");
|
||||
Locations.push_back(*NNS);
|
||||
}
|
||||
|
||||
ASTContext &Context;
|
||||
std::vector<NestedNameSpecifierLoc> Locations;
|
||||
MatchFinder Finder;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,10 +46,6 @@ namespace {
|
|||
// 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,
|
||||
|
@ -90,23 +86,11 @@ private:
|
|||
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));
|
||||
}
|
||||
USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
|
||||
}
|
||||
// If D is CXXMethodDecl we should add all USRs of its overriden methods.
|
||||
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
|
||||
|
|
|
@ -34,38 +34,18 @@ namespace {
|
|||
class USRLocFindingASTVisitor
|
||||
: public clang::RecursiveASTVisitor<USRLocFindingASTVisitor> {
|
||||
public:
|
||||
explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName)
|
||||
: USR(USR), PrevName(PrevName) {}
|
||||
explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName,
|
||||
const ASTContext &Context)
|
||||
: USR(USR), PrevName(PrevName), Context(Context) {}
|
||||
|
||||
// Declaration visitors:
|
||||
|
||||
bool VisitNamedDecl(const NamedDecl *Decl) {
|
||||
if (getUSRForDecl(Decl) == USR) {
|
||||
LocationsFound.push_back(Decl->getLocation());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitVarDecl(clang::VarDecl *Decl) {
|
||||
clang::QualType Type = Decl->getType();
|
||||
const clang::RecordDecl *RecordDecl = Type->getPointeeCXXRecordDecl();
|
||||
if (RecordDecl) {
|
||||
if (getUSRForDecl(RecordDecl) == USR) {
|
||||
// The declaration refers to a type that is to be renamed.
|
||||
LocationsFound.push_back(Decl->getTypeSpecStartLoc());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
|
||||
const ASTContext &Context = ConstructorDecl->getASTContext();
|
||||
for (auto &Initializer : ConstructorDecl->inits()) {
|
||||
if (Initializer->getSourceOrder() == -1) {
|
||||
// Ignore implicit initializers.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) {
|
||||
if (getUSRForDecl(FieldDecl) == USR) {
|
||||
// The initializer refers to a field that is to be renamed.
|
||||
|
@ -81,33 +61,13 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getUSRForDecl(ConstructorDecl) == USR) {
|
||||
// This takes care of the class name part of a non-inline ctor definition.
|
||||
LocationsFound.push_back(ConstructorDecl->getLocStart());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitCXXDestructorDecl(clang::CXXDestructorDecl *DestructorDecl) {
|
||||
if (getUSRForDecl(DestructorDecl->getParent()) == USR) {
|
||||
// Handles "~Foo" from "Foo::~Foo".
|
||||
SourceLocation Location = DestructorDecl->getLocation();
|
||||
const ASTContext &Context = DestructorDecl->getASTContext();
|
||||
StringRef LLVM_ATTRIBUTE_UNUSED TokenName = Lexer::getSourceText(
|
||||
CharSourceRange::getTokenRange(Location), Context.getSourceManager(),
|
||||
Context.getLangOpts());
|
||||
// 1 is the length of the "~" string that is not to be touched by the
|
||||
// rename.
|
||||
assert(TokenName.startswith("~"));
|
||||
LocationsFound.push_back(Location.getLocWithOffset(1));
|
||||
|
||||
if (DestructorDecl->isThisDeclarationADefinition()) {
|
||||
// Handles "Foo" from "Foo::~Foo".
|
||||
LocationsFound.push_back(DestructorDecl->getLocStart());
|
||||
}
|
||||
bool VisitNamedDecl(const NamedDecl *Decl) {
|
||||
if (getUSRForDecl(Decl) == USR) {
|
||||
checkAndAddLocation(Decl->getLocation());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -116,11 +76,10 @@ public:
|
|||
bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
|
||||
const auto *Decl = Expr->getFoundDecl();
|
||||
|
||||
checkNestedNameSpecifierLoc(Expr->getQualifierLoc());
|
||||
if (getUSRForDecl(Decl) == USR) {
|
||||
const SourceManager &Manager = Decl->getASTContext().getSourceManager();
|
||||
SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation());
|
||||
LocationsFound.push_back(Location);
|
||||
checkAndAddLocation(Location);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -131,22 +90,11 @@ public:
|
|||
if (getUSRForDecl(Decl) == USR) {
|
||||
const SourceManager &Manager = Decl->getASTContext().getSourceManager();
|
||||
SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc());
|
||||
LocationsFound.push_back(Location);
|
||||
checkAndAddLocation(Location);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitCXXConstructExpr(const CXXConstructExpr *Expr) {
|
||||
CXXConstructorDecl *Decl = Expr->getConstructor();
|
||||
|
||||
if (getUSRForDecl(Decl) == USR) {
|
||||
// This takes care of 'new <name>' expressions.
|
||||
LocationsFound.push_back(Expr->getLocation());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr *Expr) {
|
||||
return handleCXXNamedCastExpr(Expr);
|
||||
}
|
||||
|
@ -163,6 +111,15 @@ public:
|
|||
return handleCXXNamedCastExpr(Expr);
|
||||
}
|
||||
|
||||
// Other visitors:
|
||||
|
||||
bool VisitTypeLoc(const TypeLoc Loc) {
|
||||
if (getUSRForDecl(Loc.getType()->getAsCXXRecordDecl()) == USR) {
|
||||
checkAndAddLocation(Loc.getBeginLoc());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Non-visitors:
|
||||
|
||||
// \brief Returns a list of unique locations. Duplicate or overlapping
|
||||
|
@ -171,13 +128,13 @@ public:
|
|||
return LocationsFound;
|
||||
}
|
||||
|
||||
private:
|
||||
// Namespace traversal:
|
||||
void checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
|
||||
void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
|
||||
while (NameLoc) {
|
||||
const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
|
||||
if (Decl && getUSRForDecl(Decl) == USR)
|
||||
LocationsFound.push_back(NameLoc.getLocalBeginLoc());
|
||||
if (Decl && getUSRForDecl(Decl) == USR) {
|
||||
checkAndAddLocation(NameLoc.getLocalBeginLoc());
|
||||
}
|
||||
NameLoc = NameLoc.getPrefix();
|
||||
}
|
||||
}
|
||||
|
@ -194,25 +151,46 @@ private:
|
|||
if (Decl && getUSRForDecl(Decl) == USR) {
|
||||
SourceLocation Location =
|
||||
Expr->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
|
||||
LocationsFound.push_back(Location);
|
||||
checkAndAddLocation(Location);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void checkAndAddLocation(SourceLocation Loc) {
|
||||
const auto BeginLoc = Loc;
|
||||
const auto EndLoc = Lexer::getLocForEndOfToken(
|
||||
BeginLoc, 0, Context.getSourceManager(),
|
||||
Context.getLangOpts());
|
||||
StringRef TokenName =
|
||||
Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
|
||||
Context.getSourceManager(), Context.getLangOpts());
|
||||
size_t Offset = TokenName.find(PrevName);
|
||||
if (Offset != StringRef::npos) {
|
||||
// The token of the source location we find actually has the old
|
||||
// name.
|
||||
LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset));
|
||||
}
|
||||
}
|
||||
|
||||
// All the locations of the USR were found.
|
||||
const std::string USR;
|
||||
// Old name that is renamed.
|
||||
const std::string PrevName;
|
||||
std::vector<clang::SourceLocation> LocationsFound;
|
||||
const ASTContext &Context;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::vector<SourceLocation> getLocationsOfUSR(StringRef USR, StringRef PrevName,
|
||||
Decl *Decl) {
|
||||
USRLocFindingASTVisitor Visitor(USR, PrevName);
|
||||
|
||||
USRLocFindingASTVisitor Visitor(USR, PrevName, Decl->getASTContext());
|
||||
Visitor.TraverseDecl(Decl);
|
||||
NestedNameSpecifierLocFinder Finder(Decl->getASTContext());
|
||||
for (const auto &Location : Finder.getNestedNameSpecifierLocations()) {
|
||||
Visitor.handleNestedNameSpecifierLoc(Location);
|
||||
}
|
||||
return Visitor.getLocationsFound();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
class Foo {}; // CHECK: class Bar {};
|
||||
|
||||
template <typename T>
|
||||
void func() {}
|
||||
|
||||
template <typename T>
|
||||
class Baz {};
|
||||
|
||||
int main() {
|
||||
func<Foo>(); // CHECK: func<Bar>();
|
||||
Baz<Foo> obj; // CHECK: Baz<Bar> obj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use grep -FUbo 'Foo' <file> to get the correct offset of Foo when changing
|
||||
// this file.
|
|
@ -0,0 +1,20 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=304 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
class Foo {}; // CHECK: class Bar {};
|
||||
|
||||
template <typename T>
|
||||
void func() {}
|
||||
|
||||
template <typename T>
|
||||
class Baz {};
|
||||
|
||||
int main() {
|
||||
func<Foo>(); // CHECK: func<Bar>();
|
||||
Baz<Foo> obj; // CHECK: Baz<Bar> obj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use grep -FUbo 'Foo' <file> to get the correct offset of Cla when changing
|
||||
// this file.
|
|
@ -1,17 +1,10 @@
|
|||
// Currently unsupported test.
|
||||
// RUN: cat %s > %t.cpp
|
||||
// FIXME: clang-rename doesn't recognize symbol in class function definition.
|
||||
// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
class Foo {
|
||||
class Foo { // CHECK: class Bar {
|
||||
public:
|
||||
void foo(int x);
|
||||
};
|
||||
|
||||
void Foo::foo(int x) {}
|
||||
// ^ this one
|
||||
|
||||
int main() {
|
||||
Foo obj;
|
||||
obj.foo(0);
|
||||
return 0;
|
||||
}
|
||||
void Foo::foo(int x) {} // CHECK: void Bar::foo(int x) {}
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
// Unsupported test.
|
||||
// RUN: cat %s > %t.cpp
|
||||
// FIXME: This test contains very simple constructions likely to be seen in any
|
||||
// project and therefore passing this test is a slight sign of success.
|
||||
// Currently, the test fails badly.
|
||||
// RUN: clang-rename -offset=220 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
// Forward declaration.
|
||||
class Foo; // CHECK: class Bar;
|
||||
|
||||
class Foo { // CHECK: class Bar {
|
||||
public:
|
||||
Foo(int value = 0) : x(value) {} // Bar(int value=0) : x(value) {}
|
||||
public:
|
||||
Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) : x(value) {}
|
||||
|
||||
Foo& operator++(int) { // Bar& operator++(int) {
|
||||
Foo &operator++(int) { // CHECK: Bar &operator++(int) {
|
||||
x++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator<(Foo const& rhs) { // bool operator<(Bar const &rhs) {
|
||||
bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const &rhs) {
|
||||
return this->x < rhs.x;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
int x;
|
||||
};
|
||||
|
||||
int main() {
|
||||
Foo* Pointer = 0; // CHECK: Bar *Pointer = 0;
|
||||
Foo *Pointer = 0; // CHECK: Bar *Pointer = 0;
|
||||
Foo Variable = Foo(10); // CHECK: Bar Variable = Bar(10);
|
||||
for (Foo it; it < Variable; it++) { // for (Bar it; it < Variable; it++) {}
|
||||
for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it < Variable; it++) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=287 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
// Currently unsupported test.
|
||||
// FIXME: clang-rename should be able to rename classes with templates
|
||||
// correctly.
|
||||
// XFAIL: *
|
||||
|
||||
template <typename T>
|
||||
class Foo { // CHECK: class Bar;
|
||||
public:
|
||||
T foo(T arg, T& ref, T* ptr) {
|
||||
T value;
|
||||
int number = 42;
|
||||
value = (T)number;
|
||||
value = static_cast<T>(number);
|
||||
return value;
|
||||
}
|
||||
static void foo(T value) {}
|
||||
T member;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void func() {
|
||||
Foo<T> obj; // CHECK: Bar<T> obj;
|
||||
obj.member = T();
|
||||
Foo<T>::foo(); // CHECK: Bar<T>::foo();
|
||||
}
|
||||
|
||||
int main() {
|
||||
Foo<int> i; // CHECK: Bar<int> i;
|
||||
i.member = 0;
|
||||
Foo<int>::foo(0); // CHECK: Bar<int>::foo(0);
|
||||
|
||||
Foo<bool> b; // CHECK: Bar<bool> b;
|
||||
b.member = false;
|
||||
Foo<bool>::foo(false); // CHECK: Bar<bool>::foo(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use grep -FUbo 'C' <file> to get the correct offset of foo when changing
|
||||
// this file.
|
|
@ -0,0 +1,44 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=703 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
// Currently unsupported test.
|
||||
// FIXME: clang-rename should be able to rename classes with templates
|
||||
// correctly.
|
||||
// XFAIL: *
|
||||
|
||||
template <typename T>
|
||||
class Foo { // CHECK: class Bar;
|
||||
public:
|
||||
T foo(T arg, T& ref, T* ptr) {
|
||||
T value;
|
||||
int number = 42;
|
||||
value = (T)number;
|
||||
value = static_cast<T>(number);
|
||||
return value;
|
||||
}
|
||||
static void foo(T value) {}
|
||||
T member;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void func() {
|
||||
Foo<T> obj; // CHECK: Bar<T> obj;
|
||||
obj.member = T();
|
||||
Foo<T>::foo(); // CHECK: Bar<T>::foo();
|
||||
}
|
||||
|
||||
int main() {
|
||||
Foo<int> i; // CHECK: Bar<int> i;
|
||||
i.member = 0;
|
||||
Foo<int>::foo(0); // CHECK: Bar<int>::foo(0);
|
||||
|
||||
Foo<bool> b; // CHECK: Bar<bool> b;
|
||||
b.member = false;
|
||||
Foo<bool>::foo(false); // CHECK: Bar<bool>::foo(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use grep -FUbo 'Foo' <file> to get the correct offset of foo when changing
|
||||
// this file.
|
|
@ -0,0 +1,20 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=241 -new-name=bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
// FIXME: clang-rename should be able to rename functions with templates.
|
||||
// XFAIL: *
|
||||
|
||||
template <typename T>
|
||||
T foo(T value) { // CHECK: T boo(T value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
int main() {
|
||||
foo<bool>(false); // CHECK: bar<bool>(false);
|
||||
foo<int>(0); // CHECK: bar<int>(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use grep -FUbo 'foo' <file> to get the correct offset of foo when changing
|
||||
// this file.
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=290 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
// FIXME: clang-rename should be able to rename functions with templates.
|
||||
// XFAIL: *
|
||||
|
||||
template <typename T>
|
||||
T foo(T value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
int main() {
|
||||
foo<bool>(false);
|
||||
foo<int>(0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=270 -new-name=U %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
// Currently unsupported test.
|
||||
// FIXME: clang-rename should be able to rename template parameters correctly.
|
||||
// XFAIL: *
|
||||
|
||||
template <typename T> // CHECK: template <typename U>
|
||||
class Foo {
|
||||
T foo(T arg, T& ref, T* ptr) { // CHECK: U foo(U arg, U& ref, U* ptr) {
|
||||
T value; // CHECK: U value;
|
||||
int number = 42;
|
||||
value = (T)number; // CHECK: value = (U)number;
|
||||
value = static_cast<T>(number); // CHECK: value = static_cast<U>(number);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void foo(T value) {} // CHECK: static void foo(U value) {}
|
||||
|
||||
T member; // CHECK: U member;
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: cat %s > %t.cpp
|
||||
// RUN: clang-rename -offset=350 -new-name=U %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
// Currently unsupported test.
|
||||
// FIXME: clang-rename should be able to rename template parameters correctly.
|
||||
// XFAIL: *
|
||||
|
||||
template <typename T> // CHECK: template <typename U>
|
||||
class Foo {
|
||||
T foo(T arg, T& ref, T* ptr) { // CHECK: U foo(U arg, U& ref, U* ptr) {
|
||||
T value; // CHECK: U value;
|
||||
int number = 42;
|
||||
value = (T)number; // CHECK: value = (U)number;
|
||||
value = static_cast<T>(number); // CHECK: value = static_cast<U>(number);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void foo(T value) {} // CHECK: static void foo(U value) {}
|
||||
|
||||
T member; // CHECK: U member;
|
||||
};
|
|
@ -1,7 +1,6 @@
|
|||
// Currently unsupported test.
|
||||
// RUN: cat %s > %t.cpp
|
||||
// FIXME: while renaming class/struct clang-rename should be able to change
|
||||
// this type name corresponding user-defined conversions, too.
|
||||
// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i --
|
||||
// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
|
||||
|
||||
class Foo { // CHECK: class Bar {
|
||||
// ^ offset must be here
|
||||
|
@ -22,3 +21,6 @@ int main() {
|
|||
Foo foo = static_cast<Foo>(boo); // CHECK: Bar foo = static_cast<Bar>(boo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use grep -FUbo 'Foo' <file> to get the correct offset of Cla when changing
|
||||
// this file.
|
||||
|
|
Loading…
Reference in New Issue