[clang-tools-extra] r335218 - [clangd] Expose 'shouldCollectSymbol' helper from SymbolCollector.
Eric Liu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 21 05:12:26 PDT 2018
Author: ioeric
Date: Thu Jun 21 05:12:26 2018
New Revision: 335218
URL: http://llvm.org/viewvc/llvm-project?rev=335218&view=rev
Log:
[clangd] Expose 'shouldCollectSymbol' helper from SymbolCollector.
Summary: This allows tools to examine symbols that would be collected in a symbol index. For example, a tool that measures index-based completion quality would be interested in references to symbols that are collected in the index.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48418
Modified:
clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
clang-tools-extra/trunk/clangd/index/SymbolCollector.h
clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp
Modified: clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp?rev=335218&r1=335217&r2=335218&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp (original)
+++ clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp Thu Jun 21 05:12:26 2018
@@ -130,51 +130,6 @@ bool isPrivateProtoDecl(const NamedDecl
std::any_of(Name.begin(), Name.end(), islower);
}
-bool shouldFilterDecl(const NamedDecl *ND, ASTContext *ASTCtx,
- const SymbolCollector::Options &Opts) {
- using namespace clang::ast_matchers;
- if (ND->isImplicit())
- return true;
- // Skip anonymous declarations, e.g (anonymous enum/class/struct).
- if (ND->getDeclName().isEmpty())
- return true;
-
- // FIXME: figure out a way to handle internal linkage symbols (e.g. static
- // variables, function) defined in the .cc files. Also we skip the symbols
- // in anonymous namespace as the qualifier names of these symbols are like
- // `foo::<anonymous>::bar`, which need a special handling.
- // In real world projects, we have a relatively large set of header files
- // that define static variables (like "static const int A = 1;"), we still
- // want to collect these symbols, although they cause potential ODR
- // violations.
- if (ND->isInAnonymousNamespace())
- return true;
-
- // We want most things but not "local" symbols such as symbols inside
- // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl.
- // FIXME: Need a matcher for ExportDecl in order to include symbols declared
- // within an export.
- auto InNonLocalContext = hasDeclContext(anyOf(
- translationUnitDecl(), namespaceDecl(), linkageSpecDecl(), recordDecl(),
- enumDecl(), objcProtocolDecl(), objcInterfaceDecl(), objcCategoryDecl(),
- objcCategoryImplDecl(), objcImplementationDecl()));
- // Don't index template specializations and expansions in main files.
- auto IsSpecialization =
- anyOf(functionDecl(isExplicitTemplateSpecialization()),
- cxxRecordDecl(isExplicitTemplateSpecialization()),
- varDecl(isExplicitTemplateSpecialization()));
- if (match(decl(allOf(unless(isExpansionInMainFile()), InNonLocalContext,
- unless(IsSpecialization))),
- *ND, *ASTCtx)
- .empty())
- return true;
-
- // Avoid indexing internal symbols in protobuf generated headers.
- if (isPrivateProtoDecl(*ND))
- return true;
- return false;
-}
-
// We only collect #include paths for symbols that are suitable for global code
// completion, except for namespaces since #include path for a namespace is hard
// to define.
@@ -283,6 +238,52 @@ void SymbolCollector::initialize(ASTCont
llvm::make_unique<CodeCompletionTUInfo>(CompletionAllocator);
}
+bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND,
+ ASTContext &ASTCtx,
+ const Options &Opts) {
+ using namespace clang::ast_matchers;
+ if (ND.isImplicit())
+ return false;
+ // Skip anonymous declarations, e.g (anonymous enum/class/struct).
+ if (ND.getDeclName().isEmpty())
+ return false;
+
+ // FIXME: figure out a way to handle internal linkage symbols (e.g. static
+ // variables, function) defined in the .cc files. Also we skip the symbols
+ // in anonymous namespace as the qualifier names of these symbols are like
+ // `foo::<anonymous>::bar`, which need a special handling.
+ // In real world projects, we have a relatively large set of header files
+ // that define static variables (like "static const int A = 1;"), we still
+ // want to collect these symbols, although they cause potential ODR
+ // violations.
+ if (ND.isInAnonymousNamespace())
+ return false;
+
+ // We want most things but not "local" symbols such as symbols inside
+ // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl.
+ // FIXME: Need a matcher for ExportDecl in order to include symbols declared
+ // within an export.
+ auto InNonLocalContext = hasDeclContext(anyOf(
+ translationUnitDecl(), namespaceDecl(), linkageSpecDecl(), recordDecl(),
+ enumDecl(), objcProtocolDecl(), objcInterfaceDecl(), objcCategoryDecl(),
+ objcCategoryImplDecl(), objcImplementationDecl()));
+ // Don't index template specializations and expansions in main files.
+ auto IsSpecialization =
+ anyOf(functionDecl(isExplicitTemplateSpecialization()),
+ cxxRecordDecl(isExplicitTemplateSpecialization()),
+ varDecl(isExplicitTemplateSpecialization()));
+ if (match(decl(allOf(unless(isExpansionInMainFile()), InNonLocalContext,
+ unless(IsSpecialization))),
+ ND, ASTCtx)
+ .empty())
+ return false;
+
+ // Avoid indexing internal symbols in protobuf generated headers.
+ if (isPrivateProtoDecl(ND))
+ return false;
+ return true;
+}
+
// Always return true to continue indexing.
bool SymbolCollector::handleDeclOccurence(
const Decl *D, index::SymbolRoleSet Roles,
@@ -319,7 +320,7 @@ bool SymbolCollector::handleDeclOccurenc
if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
return true;
- if (shouldFilterDecl(ND, ASTCtx, Opts))
+ if (!shouldCollectSymbol(*ND, *ASTCtx, Opts))
return true;
llvm::SmallString<128> USR;
Modified: clang-tools-extra/trunk/clangd/index/SymbolCollector.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/index/SymbolCollector.h?rev=335218&r1=335217&r2=335218&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/index/SymbolCollector.h (original)
+++ clang-tools-extra/trunk/clangd/index/SymbolCollector.h Thu Jun 21 05:12:26 2018
@@ -29,7 +29,7 @@ namespace clangd {
/// - Library-specific private declarations (e.g. private declaration generated
/// by protobuf compiler)
///
-/// See also shouldFilterDecl().
+/// See also shouldCollectSymbol(...).
///
/// Clients (e.g. clangd) can use SymbolCollector together with
/// index::indexTopLevelDecls to retrieve all symbols when the source file is
@@ -56,6 +56,11 @@ public:
SymbolCollector(Options Opts);
+ /// Returns true is \p ND should be collected.
+ /// AST matchers require non-const ASTContext.
+ static bool shouldCollectSymbol(const NamedDecl &ND, ASTContext &ASTCtx,
+ const Options &Opts);
+
void initialize(ASTContext &Ctx) override;
void setPreprocessor(std::shared_ptr<Preprocessor> PP) override {
Modified: clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp?rev=335218&r1=335217&r2=335218&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp Thu Jun 21 05:12:26 2018
@@ -9,6 +9,7 @@
#include "Annotations.h"
#include "TestFS.h"
+#include "TestTU.h"
#include "index/SymbolCollector.h"
#include "index/SymbolYAML.h"
#include "clang/Basic/FileManager.h"
@@ -75,6 +76,86 @@ namespace clang {
namespace clangd {
namespace {
+
+class ShouldCollectSymbolTest : public ::testing::Test {
+public:
+ void build(StringRef HeaderCode, StringRef Code = "") {
+ File.HeaderFilename = HeaderName;
+ File.Filename = FileName;
+ File.HeaderCode = HeaderCode;
+ File.Code = Code;
+ AST = File.build();
+ }
+
+ // build() must have been called.
+ bool shouldCollect(StringRef Name, bool Qualified = true) {
+ assert(AST.hasValue());
+ return SymbolCollector::shouldCollectSymbol(
+ Qualified ? findDecl(*AST, Name) : findAnyDecl(*AST, Name),
+ AST->getASTContext(), SymbolCollector::Options());
+ }
+
+protected:
+ std::string HeaderName = "f.h";
+ std::string FileName = "f.cpp";
+ TestTU File;
+ Optional<ParsedAST> AST; // Initialized after build.
+};
+
+TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) {
+ build(R"(
+ namespace nx {
+ class X{}
+ void f() { int Local; }
+ struct { int x } var;
+ namespace { class InAnonymous {}; }
+ }
+ )",
+ "class InMain {};");
+ auto AST = File.build();
+ EXPECT_TRUE(shouldCollect("nx"));
+ EXPECT_TRUE(shouldCollect("nx::X"));
+ EXPECT_TRUE(shouldCollect("nx::f"));
+
+ EXPECT_FALSE(shouldCollect("InMain"));
+ EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false));
+ EXPECT_FALSE(shouldCollect("InAnonymous", /*Qualified=*/false));
+}
+
+TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {
+ HeaderName = "f.proto.h";
+ build(
+ R"(// Generated by the protocol buffer compiler. DO NOT EDIT!
+ namespace nx {
+ class Top_Level {};
+ class TopLevel {};
+ enum Kind {
+ KIND_OK,
+ Kind_Not_Ok,
+ };
+ })");
+ EXPECT_TRUE(shouldCollect("nx::TopLevel"));
+ EXPECT_TRUE(shouldCollect("nx::Kind::KIND_OK"));
+ EXPECT_TRUE(shouldCollect("nx::Kind"));
+
+ EXPECT_FALSE(shouldCollect("nx::Top_Level"));
+ EXPECT_FALSE(shouldCollect("nx::Kind::Kind_Not_Ok"));
+}
+
+TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
+ HeaderName = "f.proto.h";
+ build(R"(
+ namespace nx {
+ class Top_Level {};
+ enum Kind {
+ Kind_Fine
+ };
+ }
+ )");
+ EXPECT_TRUE(shouldCollect("nx::Top_Level"));
+ EXPECT_TRUE(shouldCollect("nx::Kind_Fine"));
+}
+
class SymbolIndexActionFactory : public tooling::FrontendActionFactory {
public:
SymbolIndexActionFactory(SymbolCollector::Options COpts,
@@ -865,42 +946,6 @@ TEST_F(SymbolCollectorTest, UTF16Charact
AllOf(QName("pörk"), DeclRange(Header.range()))));
}
-TEST_F(SymbolCollectorTest, FilterPrivateProtoSymbols) {
- TestHeaderName = testPath("x.proto.h");
- const std::string Header =
- R"(// Generated by the protocol buffer compiler. DO NOT EDIT!
- namespace nx {
- class Top_Level {};
- class TopLevel {};
- enum Kind {
- KIND_OK,
- Kind_Not_Ok,
- };
- bool operator<(const TopLevel &, const TopLevel &);
- })";
- runSymbolCollector(Header, /*Main=*/"");
- EXPECT_THAT(Symbols,
- UnorderedElementsAre(QName("nx"), QName("nx::TopLevel"),
- QName("nx::Kind"), QName("nx::KIND_OK"),
- QName("nx::operator<")));
-}
-
-TEST_F(SymbolCollectorTest, DoubleCheckProtoHeaderComment) {
- TestHeaderName = testPath("x.proto.h");
- const std::string Header = R"(
- namespace nx {
- class Top_Level {};
- enum Kind {
- Kind_Fine
- };
- }
- )";
- runSymbolCollector(Header, /*Main=*/"");
- EXPECT_THAT(Symbols,
- UnorderedElementsAre(QName("nx"), QName("nx::Top_Level"),
- QName("nx::Kind"), QName("nx::Kind_Fine")));
-}
-
TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
Annotations Header(R"(
namespace nx {
More information about the cfe-commits
mailing list