}
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:
// \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:
// 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());
Decl->getNameAsString().length());
}
- // Other:
+ // Other visitors:
- const NamedDecl *getNamedDecl() {
- return Result;
+ 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);
}
-private:
+ // Other:
+
+ const NamedDecl *getNamedDecl() { return Result; }
+
// \brief Determines if a namespace qualifier contains the point.
// \returns false on success and sets Result.
- bool checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
+ void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
while (NameLoc) {
const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
- if (Decl && !setResult(Decl, NameLoc.getLocalBeginLoc(),
- Decl->getNameAsString().length()))
- return false;
+ if (Decl) {
+ setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc());
+ }
NameLoc = NameLoc.getPrefix();
}
- return true;
}
+private:
// \brief Sets Result to Decl if the Point is within Start and End.
// \returns false on success.
bool setResult(const NamedDecl *Decl, SourceLocation Start,
// \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));
const SourceManager &SourceMgr;
const SourceLocation Point; // The location to find the NamedDecl.
const std::string Name;
+ const ASTContext *Context;
};
} // namespace
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();
// 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();
-
- for (auto &CurrDecl : Decls) {
- Visitor.TraverseDecl(CurrDecl);
- if (const NamedDecl *Result = Visitor.getNamedDecl()) {
- return Result;
- }
- }
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
- return nullptr;
+ return Visitor.getNamedDecl();
}
std::string getUSRForDecl(const Decl *Decl) {
#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;
// 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;
+};
+
}
}
// 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,
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)) {
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.
}
}
}
-
- 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;
}
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;
if (getUSRForDecl(Decl) == USR) {
const SourceManager &Manager = Decl->getASTContext().getSourceManager();
SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc());
- LocationsFound.push_back(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());
+ checkAndAddLocation(Location);
}
-
return true;
}
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
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();
}
}
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();
}
--- /dev/null
+// 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.
--- /dev/null
+// 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.
-// 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) {}
-// 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;
}
--- /dev/null
+// 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.
--- /dev/null
+// 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.
--- /dev/null
+// 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.
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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;
+};
--- /dev/null
+// 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;
+};
-// 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
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.