diff options
author | Eric Liu <ioeric@google.com> | 2018-02-02 10:31:42 +0000 |
---|---|---|
committer | Eric Liu <ioeric@google.com> | 2018-02-02 10:31:42 +0000 |
commit | cf1773826fd815bf1c8ddc964f4c9f1b5b47b978 (patch) | |
tree | 4bb743209d4513a3d6f2d7a5519d06c5136c90f4 | |
parent | 436046630dd197a3ef4e0c6c2adb44e6f4b1c616 (diff) | |
download | bcm5719-llvm-cf1773826fd815bf1c8ddc964f4c9f1b5b47b978.tar.gz bcm5719-llvm-cf1773826fd815bf1c8ddc964f4c9f1b5b47b978.zip |
[clangd] Skip inline namespace when collecting scopes for index symbols.
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
-rw-r--r-- | clang-tools-extra/clangd/index/SymbolCollector.cpp | 17 | ||||
-rw-r--r-- | clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp | 50 |
2 files changed, 62 insertions, 5 deletions
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index b6673073d56..9f35380708b 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -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" @@ -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())), @@ -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); diff --git a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp index df55cb225e7..45dabf6d993 100644 --- a/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp +++ b/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp @@ -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) { @@ -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 { |