From 638fa18e43f75f71bdaf28da6b8307976abab8a0 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Tue, 26 Jul 2016 14:53:05 +0000 Subject: [PATCH] [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 --- lib/Tooling/Core/Lookup.cpp | 45 ++++++++++++++++++++------------ unittests/Tooling/LookupTest.cpp | 8 ++++++ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/lib/Tooling/Core/Lookup.cpp b/lib/Tooling/Core/Lookup.cpp index 697eeb46ce..84135f441d 100644 --- a/lib/Tooling/Core/Lookup.cpp +++ b/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 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 on DeclB. - while (DeclB && !isa(DeclB)) - DeclB = DeclB->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 @@ std::string tooling::replaceNestedName(const NestedNameSpecifier *Use, 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; diff --git a/unittests/Tooling/LookupTest.cpp b/unittests/Tooling/LookupTest.cpp index d847a298ff..842d587e9a 100644 --- a/unittests/Tooling/LookupTest.cpp +++ b/unittests/Tooling/LookupTest.cpp @@ -103,6 +103,14 @@ TEST(LookupTest, replaceNestedName) { }; 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 -- 2.40.0