summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Liu <ioeric@google.com>2018-02-02 10:31:42 +0000
committerEric Liu <ioeric@google.com>2018-02-02 10:31:42 +0000
commitcf1773826fd815bf1c8ddc964f4c9f1b5b47b978 (patch)
tree4bb743209d4513a3d6f2d7a5519d06c5136c90f4
parent436046630dd197a3ef4e0c6c2adb44e6f4b1c616 (diff)
downloadbcm5719-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.cpp17
-rw-r--r--clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp50
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 {
OpenPOWER on IntegriCloud