Author: ioeric Date: Tue Jul 26 09:53:05 2016 New Revision: 276754 URL: http://llvm.org/viewvc/llvm-project?rev=276754&view=rev Log: [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 Modified: cfe/trunk/lib/Tooling/Core/Lookup.cpp cfe/trunk/unittests/Tooling/LookupTest.cpp Modified: cfe/trunk/lib/Tooling/Core/Lookup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Core/Lookup.cpp?rev=276754&r1=276753&r2=276754&view=diff ============================================================================== --- cfe/trunk/lib/Tooling/Core/Lookup.cpp (original) +++ cfe/trunk/lib/Tooling/Core/Lookup.cpp Tue Jul 26 09:53:05 2016 @@ -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<NamespaceDecl>(DeclA)) - DeclA = DeclA->getParent(); - - // Look past non-namespaces on DeclB. - while (DeclB && !isa<NamespaceDecl>(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<NamespaceDecl>(FromContext) || + cast<NamespaceDecl>(FromContext)->isAnonymousNamespace())) + FromContext = FromContext->getParent(); + + // Look past non-namespaces and anonymous namespaces on UseContext. + while (UseContext && + (!isa<NamespaceDecl>(UseContext) || + cast<NamespaceDecl>(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<NamespaceDecl>(DeclA)->getDeclName() == - cast<NamespaceDecl>(DeclB)->getDeclName()) + if (cast<NamespaceDecl>(FromContext)->getDeclName() == + cast<NamespaceDecl>(UseContext)->getDeclName()) return true; - DeclA = DeclA->getParent(); - DeclB = DeclB->getParent(); + FromContext = FromContext->getParent(); + UseContext = UseContext->getParent(); } } @@ -98,8 +111,8 @@ std::string tooling::replaceNestedName(c const bool in_global_namespace = isa<TranslationUnitDecl>(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; Modified: cfe/trunk/unittests/Tooling/LookupTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/LookupTest.cpp?rev=276754&r1=276753&r2=276754&view=diff ============================================================================== --- cfe/trunk/unittests/Tooling/LookupTest.cpp (original) +++ cfe/trunk/unittests/Tooling/LookupTest.cpp Tue Jul 26 09:53:05 2016 @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits