Skip to content

Commit

Permalink
[clangd] Skip inline namespace when collecting scopes for index symbols.
Browse files Browse the repository at this point in the history
Summary:
Some STL symbols are defined in inline namespaces. For example,
```
namespace std {
inline namespace __cxx11 {
 typedef ... string;
}
}
```
Currently, this will be `std::__cxx11::string`; however, `std::string` is desired.

Inline namespaces are treated as transparent scopes. This
reflects the way they're most commonly used for lookup. Ideally we'd
include them, but at query time it's hard to find all the inline
namespaces to query: the preamble doesn't have a dedicated list.

Reviewers: sammccall, hokein

Reviewed By: sammccall

Subscribers: klimek, ilya-biryukov, jkorous-apple, cfe-commits

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

llvm-svn: 324065
  • Loading branch information
Eric Liu committed Feb 2, 2018
1 parent 4360466 commit cf17738
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 5 deletions.
17 changes: 14 additions & 3 deletions clang-tools-extra/clangd/index/SymbolCollector.cpp
Expand Up @@ -9,6 +9,7 @@

#include "SymbolCollector.h"
#include "../CodeCompletionStrings.h"
#include "Logger.h"
#include "clang/AST/DeclCXX.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceManager.h"
Expand Down Expand Up @@ -97,8 +98,8 @@ bool shouldFilterDecl(const NamedDecl *ND, ASTContext *ASTCtx,
// * symbols in namespaces or translation unit scopes (e.g. no class
// members)
// * enum constants in unscoped enum decl (e.g. "red" in "enum {red};")
auto InTopLevelScope =
hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
auto InTopLevelScope = hasDeclContext(
anyOf(namespaceDecl(), translationUnitDecl(), linkageSpecDecl()));
if (match(decl(allOf(Opts.IndexMainFiles
? decl()
: decl(unless(isExpansionInMainFile())),
Expand Down Expand Up @@ -180,7 +181,17 @@ bool SymbolCollector::handleDeclOccurence(
return true;

auto &SM = ND->getASTContext().getSourceManager();
std::string QName = ND->getQualifiedNameAsString();

std::string QName;
llvm::raw_string_ostream OS(QName);
PrintingPolicy Policy(ASTCtx->getLangOpts());
// Note that inline namespaces are treated as transparent scopes. This
// reflects the way they're most commonly used for lookup. Ideally we'd
// include them, but at query time it's hard to find all the inline
// namespaces to query: the preamble doesn't have a dedicated list.
Policy.SuppressUnwrittenScope = true;
ND->printQualifiedName(OS, Policy);
OS.flush();

Symbol S;
S.ID = std::move(ID);
Expand Down
50 changes: 48 additions & 2 deletions clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp
Expand Up @@ -198,8 +198,7 @@ TEST_F(SymbolCollectorTest, IncludeEnums) {
runSymbolCollector(Header, /*Main=*/"");
EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Red"), QName("Color"),
QName("Green"), QName("Color2"),
QName("ns"),
QName("ns::Black")));
QName("ns"), QName("ns::Black")));
}

TEST_F(SymbolCollectorTest, IgnoreNamelessSymbols) {
Expand Down Expand Up @@ -321,6 +320,53 @@ TEST_F(SymbolCollectorTest, IgnoreClassMembers) {
EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo")));
}

TEST_F(SymbolCollectorTest, Scopes) {
const std::string Header = R"(
namespace na {
class Foo {};
namespace nb {
class Bar {};
}
}
)";
runSymbolCollector(Header, /*Main=*/"");
EXPECT_THAT(Symbols,
UnorderedElementsAre(QName("na"), QName("na::nb"),
QName("na::Foo"), QName("na::nb::Bar")));
}

TEST_F(SymbolCollectorTest, ExternC) {
const std::string Header = R"(
extern "C" { class Foo {}; }
namespace na {
extern "C" { class Bar {}; }
}
)";
runSymbolCollector(Header, /*Main=*/"");
EXPECT_THAT(Symbols,
UnorderedElementsAre(QName("na"), QName("Foo"), QName("Bar")));
}

TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
const std::string Header = R"(
namespace na {
inline namespace nb {
class Foo {};
}
}
namespace na {
// This is still inlined.
namespace nb {
class Bar {};
}
}
)";
runSymbolCollector(Header, /*Main=*/"");
EXPECT_THAT(Symbols,
UnorderedElementsAre(QName("na"), QName("na::nb"),
QName("na::Foo"), QName("na::Bar")));
}

TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
const std::string Header = R"(
namespace nx {
Expand Down

0 comments on commit cf17738

Please sign in to comment.