Skip to content
Snippets Groups Projects
Commit 638fa18e authored by Eric Liu's avatar Eric Liu
Browse files

[Tooling] skip anonymous namespaces when checking if typeLoc references a type...

[Tooling] skip anonymous namespaces when checking if typeLoc references a type decl from a different canonical namespace.

Summary:
[Tooling] skip anonymous namespaces when checking if typeLoc
references a type decl from a different canonical namespace.

Reviewers: bkramer

Subscribers: cfe-commits, klimek

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@276754 91177308-0d34-0410-b5e6-96231b3b80d8
parent e34b8a83
No related branches found
No related tags found
No related merge requests found
...@@ -16,33 +16,46 @@ ...@@ -16,33 +16,46 @@
using namespace clang; using namespace clang;
using namespace clang::tooling; using namespace clang::tooling;
static bool isInsideDifferentNamespaceWithSameName(const DeclContext *DeclA, // Returns true if the context in which the type is used and the context in
const DeclContext *DeclB) { // which the type is declared are the same semantical namespace but different
// lexical namespaces.
static bool
usingFromDifferentCanonicalNamespace(const DeclContext *FromContext,
const DeclContext *UseContext) {
while (true) { while (true) {
// Look past non-namespaces on DeclA. // Look past non-namespaces and anonymous namespaces on FromContext.
while (DeclA && !isa<NamespaceDecl>(DeclA)) // We can skip anonymous namespace because:
DeclA = DeclA->getParent(); // 1. `FromContext` and `UseContext` must be in the same anonymous
// namespaces since referencing across anonymous namespaces is not possible.
// 2. If `FromContext` and `UseContext` are in the same anonymous namespace,
// the function will still return `false` as expected.
while (FromContext &&
(!isa<NamespaceDecl>(FromContext) ||
cast<NamespaceDecl>(FromContext)->isAnonymousNamespace()))
FromContext = FromContext->getParent();
// Look past non-namespaces on DeclB. // Look past non-namespaces and anonymous namespaces on UseContext.
while (DeclB && !isa<NamespaceDecl>(DeclB)) while (UseContext &&
DeclB = DeclB->getParent(); (!isa<NamespaceDecl>(UseContext) ||
cast<NamespaceDecl>(UseContext)->isAnonymousNamespace()))
UseContext = UseContext->getParent();
// We hit the root, no namespace collision. // We hit the root, no namespace collision.
if (!DeclA || !DeclB) if (!FromContext || !UseContext)
return false; return false;
// Literally the same namespace, not a collision. // Literally the same namespace, not a collision.
if (DeclA == DeclB) if (FromContext == UseContext)
return false; return false;
// Now check the names. If they match we have a different namespace with the // Now check the names. If they match we have a different namespace with the
// same name. // same name.
if (cast<NamespaceDecl>(DeclA)->getDeclName() == if (cast<NamespaceDecl>(FromContext)->getDeclName() ==
cast<NamespaceDecl>(DeclB)->getDeclName()) cast<NamespaceDecl>(UseContext)->getDeclName())
return true; return true;
DeclA = DeclA->getParent(); FromContext = FromContext->getParent();
DeclB = DeclB->getParent(); UseContext = UseContext->getParent();
} }
} }
...@@ -98,8 +111,8 @@ std::string tooling::replaceNestedName(const NestedNameSpecifier *Use, ...@@ -98,8 +111,8 @@ std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
const bool in_global_namespace = const bool in_global_namespace =
isa<TranslationUnitDecl>(FromDecl->getDeclContext()); isa<TranslationUnitDecl>(FromDecl->getDeclContext());
if (class_name_only && !in_global_namespace && if (class_name_only && !in_global_namespace &&
!isInsideDifferentNamespaceWithSameName(FromDecl->getDeclContext(), !usingFromDifferentCanonicalNamespace(FromDecl->getDeclContext(),
UseContext)) { UseContext)) {
auto Pos = ReplacementString.rfind("::"); auto Pos = ReplacementString.rfind("::");
return Pos != StringRef::npos ? ReplacementString.substr(Pos + 2) return Pos != StringRef::npos ? ReplacementString.substr(Pos + 2)
: ReplacementString; : ReplacementString;
......
...@@ -103,6 +103,14 @@ TEST(LookupTest, replaceNestedName) { ...@@ -103,6 +103,14 @@ TEST(LookupTest, replaceNestedName) {
}; };
Visitor.runOver( Visitor.runOver(
"namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n"); "namespace a { int foo(); }\nusing a::foo;\nauto f = foo();\n");
Visitor.OnCall = [&](CallExpr *Expr) {
EXPECT_EQ("c::bar", replaceCallExpr(Expr, "::a::c::bar"));
};
Visitor.runOver("namespace a { namespace b { void foo(); } }\n"
"namespace a { namespace b { namespace {"
"void f() { foo(); }"
"} } }\n");
} }
} // end anonymous namespace } // end anonymous namespace
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment