Index: cfe/trunk/lib/Tooling/Core/Lookup.cpp =================================================================== --- cfe/trunk/lib/Tooling/Core/Lookup.cpp +++ cfe/trunk/lib/Tooling/Core/Lookup.cpp @@ -16,33 +16,46 @@ using namespace clang; using namespace clang::tooling; -static bool isInsideDifferentNamespaceWithSameName(const DeclContext *DeclA, - const DeclContext *DeclB) { +// Returns true if the context in which the type is used and the context in +// 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) { - // Look past non-namespaces on DeclA. - while (DeclA && !isa(DeclA)) - DeclA = DeclA->getParent(); - - // Look past non-namespaces on DeclB. - while (DeclB && !isa(DeclB)) - DeclB = DeclB->getParent(); + // Look past non-namespaces and anonymous namespaces on FromContext. + // We can skip anonymous namespace because: + // 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(FromContext) || + cast(FromContext)->isAnonymousNamespace())) + FromContext = FromContext->getParent(); + + // Look past non-namespaces and anonymous namespaces on UseContext. + while (UseContext && + (!isa(UseContext) || + cast(UseContext)->isAnonymousNamespace())) + UseContext = UseContext->getParent(); // We hit the root, no namespace collision. - if (!DeclA || !DeclB) + if (!FromContext || !UseContext) return false; // Literally the same namespace, not a collision. - if (DeclA == DeclB) + if (FromContext == UseContext) return false; // Now check the names. If they match we have a different namespace with the // same name. - if (cast(DeclA)->getDeclName() == - cast(DeclB)->getDeclName()) + if (cast(FromContext)->getDeclName() == + cast(UseContext)->getDeclName()) return true; - DeclA = DeclA->getParent(); - DeclB = DeclB->getParent(); + FromContext = FromContext->getParent(); + UseContext = UseContext->getParent(); } } @@ -98,8 +111,8 @@ const bool in_global_namespace = isa(FromDecl->getDeclContext()); if (class_name_only && !in_global_namespace && - !isInsideDifferentNamespaceWithSameName(FromDecl->getDeclContext(), - UseContext)) { + !usingFromDifferentCanonicalNamespace(FromDecl->getDeclContext(), + UseContext)) { auto Pos = ReplacementString.rfind("::"); return Pos != StringRef::npos ? ReplacementString.substr(Pos + 2) : ReplacementString; Index: cfe/trunk/unittests/Tooling/LookupTest.cpp =================================================================== --- cfe/trunk/unittests/Tooling/LookupTest.cpp +++ cfe/trunk/unittests/Tooling/LookupTest.cpp @@ -103,6 +103,14 @@ }; Visitor.runOver( "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