[change-namespace] do not fix calls to overloaded operator functions.

Summary: Also make sure one function reference is only processed once.

Reviewers: hokein

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D27982

llvm-svn: 290176
This commit is contained in:
Eric Liu 2016-12-20 14:39:04 +00:00
parent 2a6de8c321
commit e3f35e4db6
3 changed files with 58 additions and 0 deletions

View File

@ -481,6 +481,11 @@ void ChangeNamespaceTool::run(
llvm::cast<NamedDecl>(Var), VarRef);
} else if (const auto *FuncRef =
Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
// If this reference has been processed as a function call, we do not
// process it again.
if (ProcessedFuncRefs.count(FuncRef))
return;
ProcessedFuncRefs.insert(FuncRef);
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
assert(Func);
const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
@ -490,8 +495,16 @@ void ChangeNamespaceTool::run(
} else {
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
assert(Call != nullptr && "Expecting callback for CallExpr.");
const auto *CalleeFuncRef =
llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
ProcessedFuncRefs.insert(CalleeFuncRef);
const FunctionDecl *Func = Call->getDirectCallee();
assert(Func != nullptr);
// FIXME: ignore overloaded operators. This would miss cases where operators
// are called by qualified names (i.e. "ns::operator <"). Ignore such
// cases for now.
if (Func->isOverloadedOperator())
return;
// Ignore out-of-line static methods since they will be handled by nested
// name specifiers.
if (Func->getCanonicalDecl()->getStorageClass() ==

View File

@ -157,6 +157,10 @@ private:
// TypeLocs of CXXCtorInitializer. Types of CXXCtorInitializers do not need to
// be fixed.
llvm::SmallVector<TypeLoc, 8> BaseCtorInitializerTypeLocs;
// Since a DeclRefExpr for a function call can be matched twice (one as
// CallExpr and one as DeclRefExpr), we record all DeclRefExpr's that have
// been processed so that we don't handle them twice.
llvm::SmallPtrSet<const clang::DeclRefExpr*, 16> ProcessedFuncRefs;
};
} // namespace change_namespace

View File

@ -575,6 +575,47 @@ TEST_F(ChangeNamespaceTest, FixFunctionNameSpecifiers) {
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
}
TEST_F(ChangeNamespaceTest, FixOverloadedOperatorFunctionNameSpecifiers) {
std::string Code =
"namespace na {\n"
"class A {\n"
"public:\n"
" int x;\n"
" bool operator==(const A &RHS) const { return x == RHS.x; }\n"
"};\n"
"bool operator<(const A &LHS, const A &RHS) { return LHS.x == RHS.x; }\n"
"namespace nb {\n"
"bool f() {\n"
" A x, y;\n"
" auto f = operator<;\n"
" return (x == y) && (x < y) && (operator<(x, y));\n"
"}\n"
"} // namespace nb\n"
"} // namespace na\n";
std::string Expected =
"namespace na {\n"
"class A {\n"
"public:\n"
" int x;\n"
" bool operator==(const A &RHS) const { return x == RHS.x; }\n"
"};\n"
"bool operator<(const A &LHS, const A &RHS) { return LHS.x == RHS.x; }\n"
"\n"
"} // namespace na\n"
"namespace x {\n"
"namespace y {\n"
"bool f() {\n"
" ::na::A x, y;\n"
" auto f = ::na::operator<;\n"
// FIXME: function calls to overloaded operators are not fixed now even if
// they are referenced by qualified names.
" return (x == y) && (x < y) && (operator<(x,y));\n"
"}\n"
"} // namespace y\n"
"} // namespace x\n";
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
}
TEST_F(ChangeNamespaceTest, FixNonCallingFunctionReferences) {
std::string Code = "namespace na {\n"
"class A {\n"