sammccall created this revision.
Herald added subscribers: usaxena95, kadircet, arphaman, mgrang, javed.absar,
mgorny.
sammccall requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.
To be split
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D115232
Files:
clang-tools-extra/clangd/AST.cpp
clang-tools-extra/clangd/AST.h
clang-tools-extra/clangd/CMakeLists.txt
clang-tools-extra/clangd/ClangdServer.cpp
clang-tools-extra/clangd/Config.h
clang-tools-extra/clangd/ConfigCompile.cpp
clang-tools-extra/clangd/ConfigFragment.h
clang-tools-extra/clangd/ConfigYAML.cpp
clang-tools-extra/clangd/FS.cpp
clang-tools-extra/clangd/FS.h
clang-tools-extra/clangd/SourceCode.h
clang-tools-extra/clangd/TUScheduler.cpp
clang-tools-extra/clangd/TUScheduler.h
clang-tools-extra/clangd/index/Background.cpp
clang-tools-extra/clangd/index/FileIndex.cpp
clang-tools-extra/clangd/index/FileIndex.h
clang-tools-extra/clangd/index/StdLib.cpp
clang-tools-extra/clangd/index/StdLib.h
clang-tools-extra/clangd/index/SymbolCollector.cpp
clang-tools-extra/clangd/index/SymbolCollector.h
clang-tools-extra/clangd/index/SymbolOrigin.cpp
clang-tools-extra/clangd/index/SymbolOrigin.h
clang-tools-extra/clangd/unittests/CMakeLists.txt
clang-tools-extra/clangd/unittests/StdLibIndexTests.cpp
clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
Index: clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -1121,7 +1121,8 @@
public:
BlockPreambleThread(llvm::StringRef BlockVersion, Notification &N)
: BlockVersion(BlockVersion), N(N) {}
- void onPreambleAST(PathRef Path, llvm::StringRef Version, ASTContext &Ctx,
+ void onPreambleAST(PathRef Path, llvm::StringRef Version,
+ const CompilerInvocation &, ASTContext &Ctx,
std::shared_ptr<clang::Preprocessor> PP,
const CanonicalIncludes &) override {
if (Version == BlockVersion)
Index: clang-tools-extra/clangd/unittests/StdLibIndexTests.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/unittests/StdLibIndexTests.cpp
@@ -0,0 +1,101 @@
+//===-- StdLibIndexTests.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Compiler.h"
+#include "Config.h"
+#include "TestFS.h"
+#include "index/StdLib.h"
+#include "clang/Basic/LangStandard.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace testing;
+
+namespace clang {
+namespace clangd {
+namespace {
+
+/// check that the generated header sources contains some usual standard library
+/// headers
+TEST(StdLibIndexTests, generateUmbrellaHeader) {
+ auto CXX = generateUmbrellaHeaders(LangStandard::lang_cxx14).str();
+ EXPECT_THAT(CXX, HasSubstr("#include <string>"));
+ EXPECT_THAT(CXX, HasSubstr("#include <cstdio>"));
+ EXPECT_THAT(CXX, Not(HasSubstr("#include <stdio.h>")));
+
+ auto C = generateUmbrellaHeaders(LangStandard::lang_c11).str();
+ EXPECT_THAT(C, Not(HasSubstr("#include <string>")));
+ EXPECT_THAT(C, Not(HasSubstr("#include <cstdio>")));
+ EXPECT_THAT(C, HasSubstr("#include <stdio.h>"));
+}
+
+MATCHER_P(Named, Name, "") { return arg.Name == Name; }
+
+/// build the index and check if it contains the right symbols
+TEST(StdLibIndexTests, buildIndex) {
+ MockFS FS;
+ // TODO: maybe find a way to use a local libcxx for testing if that is
+ // available on the machine
+ std::string HeaderMock = R"CPP(
+ #if __cplusplus >= 201703L
+ int func17();
+ #elif __cplusplus >= 201402L
+ int func14();
+ #else
+ bool func98();
+ #endif
+ int __implementation_details();
+ )CPP";
+ StdlibIndexSpec Spec;
+ Spec.LangStd = LangStandard::lang_cxx14;
+ auto Symbols = indexUmbrellaHeaders(HeaderMock, FS, Spec);
+
+ EXPECT_THAT(Symbols, ElementsAre(Named("func14")));
+}
+
+CompilerInvocation parse(std::vector<std::string> Flags) {
+ ParseInputs Inputs;
+ Inputs.CompileCommand.Filename = testPath(Flags.back());
+ Inputs.CompileCommand.Directory = testRoot();
+ Inputs.CompileCommand.CommandLine = std::move(Flags);
+ MockFS FS;
+ Inputs.TFS = &FS;
+ IgnoreDiagnostics IgnoreDiags;
+ auto Result = buildCompilerInvocation(Inputs, IgnoreDiags);
+ EXPECT_TRUE(Result);
+ return *Result;
+}
+
+TEST(StdLibIndexTests, Detect) {
+ {
+ Config Cfg;
+ Cfg.Index.StandardLibrary = false;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ EXPECT_FALSE(StdlibIndexSpec::detect(parse({"clang++", "test.cc"})));
+ }
+ Config Cfg;
+ Cfg.Index.StandardLibrary = true;
+ WithContextValue WithCfg(Config::Key, std::move(Cfg));
+ EXPECT_TRUE(StdlibIndexSpec::detect(parse({"clang++", "test.cc"})));
+
+ auto CXX11 =
+ StdlibIndexSpec::detect(parse({"clang++", "-std=gnu++11", "test.cc"}));
+ EXPECT_EQ(CXX11->LangStd, LangStandard::lang_cxx11);
+
+ auto C11 = StdlibIndexSpec::detect(parse({"clang", "-std=c11", "test.c"}));
+ EXPECT_EQ(C11->LangStd, LangStandard::lang_c17); // No new features in 17.
+
+ auto WithSysroot = StdlibIndexSpec::detect(
+ parse({"clang++", "-isysroot", testPath("blah"), "test.cc"}));
+ EXPECT_EQ(testPath("blah"), WithSysroot->Sysroot);
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
Index: clang-tools-extra/clangd/unittests/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -80,6 +80,7 @@
SemanticSelectionTests.cpp
SerializationTests.cpp
SourceCodeTests.cpp
+ StdLibIndexTests.cpp
SymbolCollectorTests.cpp
SymbolInfoTests.cpp
SyncAPI.cpp
Index: clang-tools-extra/clangd/index/SymbolOrigin.h
===================================================================
--- clang-tools-extra/clangd/index/SymbolOrigin.h
+++ clang-tools-extra/clangd/index/SymbolOrigin.h
@@ -18,27 +18,30 @@
// Describes the source of information about a symbol.
// Mainly useful for debugging, e.g. understanding code completion results.
// This is a bitfield as information can be combined from several sources.
-enum class SymbolOrigin : uint8_t {
+enum class SymbolOrigin : uint16_t {
Unknown = 0,
AST = 1 << 0, // Directly from the AST (indexes should not set this).
- Dynamic = 1 << 1, // From the dynamic index of opened files.
+ Preamble = 1 << 1, // From the dynamic index of opened file preambles.
Static = 1 << 2, // From the static, externally-built index.
Merge = 1 << 3, // A non-trivial index merge was performed.
Identifier = 1 << 4, // Raw identifiers in file.
Remote = 1 << 5, // Remote index.
- // Remaining bits reserved for index implementations.
+ Open = 1 << 6, // From the dynamic index of opened files.
+ // 1 << 7 reserved
+ StdLib = 1 << 8, // Standard library indexer
+ Background = 1 << 9, // Background indexer for project
};
inline SymbolOrigin operator|(SymbolOrigin A, SymbolOrigin B) {
- return static_cast<SymbolOrigin>(static_cast<uint8_t>(A) |
- static_cast<uint8_t>(B));
+ return static_cast<SymbolOrigin>(static_cast<uint16_t>(A) |
+ static_cast<uint16_t>(B));
}
inline SymbolOrigin &operator|=(SymbolOrigin &A, SymbolOrigin B) {
return A = A | B;
}
inline SymbolOrigin operator&(SymbolOrigin A, SymbolOrigin B) {
- return static_cast<SymbolOrigin>(static_cast<uint8_t>(A) &
- static_cast<uint8_t>(B));
+ return static_cast<SymbolOrigin>(static_cast<uint16_t>(A) &
+ static_cast<uint16_t>(B));
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &, SymbolOrigin);
Index: clang-tools-extra/clangd/index/SymbolOrigin.cpp
===================================================================
--- clang-tools-extra/clangd/index/SymbolOrigin.cpp
+++ clang-tools-extra/clangd/index/SymbolOrigin.cpp
@@ -14,9 +14,9 @@
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SymbolOrigin O) {
if (O == SymbolOrigin::Unknown)
return OS << "unknown";
- constexpr static char Sigils[] = "ADSMIR67";
+ constexpr static char Sigils[] = "APSMIRO7LB012345";
for (unsigned I = 0; I < sizeof(Sigils); ++I)
- if (static_cast<uint8_t>(O) & 1u << I)
+ if (static_cast<uint16_t>(O) & 1u << I)
OS << Sigils[I];
return OS;
}
Index: clang-tools-extra/clangd/index/SymbolCollector.h
===================================================================
--- clang-tools-extra/clangd/index/SymbolCollector.h
+++ clang-tools-extra/clangd/index/SymbolCollector.h
@@ -85,6 +85,10 @@
/// Note that documents of symbols being indexed for completion will always
/// be collected regardless of this option.
bool StoreAllDocumentation = false;
+ /// Collect symbols with reserved names like __Vector_base.
+ /// These are often private parts of library implementations.
+ /// This *doesn't* currently affect macros, which are more often interfaces!
+ bool CollectReservedSymbols = false;
/// If this is set, only collect symbols/references from a file if
/// `FileFilter(SM, FID)` is true. If not set, all files are indexed.
std::function<bool(const SourceManager &, FileID)> FileFilter = nullptr;
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===================================================================
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -310,6 +310,36 @@
std::make_unique<CodeCompletionTUInfo>(CompletionAllocator);
}
+static bool shouldCollectDC(const DeclContext &DC,
+ const SymbolCollector::Options &Opts) {
+ // 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.
+ switch (DC.getDeclKind()) {
+ case Decl::TranslationUnit:
+ case Decl::Namespace:
+ case Decl::LinkageSpec:
+ case Decl::Enum:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCInterface:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ break;
+ default:
+ // Record has a few derivations (e.g. CXXRecord, Class specialization), it's
+ // easier to cast.
+ if (!isa<RecordDecl>(DC))
+ return false;
+ }
+
+ if (!Opts.CollectReservedSymbols && hasReservedScopeName(DC))
+ return false;
+
+ return true;
+}
+
bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND,
const ASTContext &ASTCtx,
const Options &Opts,
@@ -331,32 +361,14 @@
return isa<RecordDecl>(ND) ||
(ND.isCXXInstanceMember() && ND.isFunctionOrFunctionTemplate());
- // 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.
- const auto *DeclCtx = ND.getDeclContext();
- switch (DeclCtx->getDeclKind()) {
- case Decl::TranslationUnit:
- case Decl::Namespace:
- case Decl::LinkageSpec:
- case Decl::Enum:
- case Decl::ObjCProtocol:
- case Decl::ObjCInterface:
- case Decl::ObjCCategory:
- case Decl::ObjCCategoryImpl:
- case Decl::ObjCImplementation:
- break;
- default:
- // Record has a few derivations (e.g. CXXRecord, Class specialization), it's
- // easier to cast.
- if (!isa<RecordDecl>(DeclCtx))
- return false;
- }
-
// Avoid indexing internal symbols in protobuf generated headers.
if (isPrivateProtoDecl(ND))
return false;
+ if (!Opts.CollectReservedSymbols && hasReservedName(ND))
+ return false;
+ if (!shouldCollectDC(*ND.getDeclContext(), Opts))
+ return false;
+
return true;
}
Index: clang-tools-extra/clangd/index/StdLib.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/index/StdLib.h
@@ -0,0 +1,87 @@
+//===--- StdLib.h ------------------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Clangd indexer for the C++ standard library.
+//
+// The index only contains symbols that are part of the translation unit. So
+// if your translation unit does not yet #include <string>, you do not get
+// auto completion for std::string. However we expect that many users would
+// like to use the the standard library anyway, so we could index that by
+// default an offer e.g. code completion without requiring #includes.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_STDLIB_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_STDLIB_H
+
+#include "index/Symbol.h"
+#include "support/ThreadsafeFS.h"
+#include "clang/Basic/LangStandard.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace clang {
+class CompilerInvocation;
+class LangOptions;
+class HeaderSearch;
+namespace clangd {
+
+struct StdLibLocation {
+ llvm::SmallVector<std::string> Paths;
+};
+
+class StdLibSet {
+ std::atomic<int> Best[2] = {{-1}, {-1}};
+
+public:
+ // Determines if we should index the standard library in a configuration.
+ //
+ // This is true if:
+ // - standard library indexing is enabled for the file
+ // - the language version is higher than any previous add() for the language
+ // - the standard library headers exist on the search path
+ //
+ // This function is threadsafe.
+ llvm::Optional<StdLibLocation> add(const LangOptions &, const HeaderSearch &);
+
+ // Indicates whether we a built index should be used.
+ // It should not be used if a newer version has subsequently been added.
+ //
+ // Intended pattern is:
+ // if (add()) {
+ // symbols = indexStandardLibrary();
+ // if (isBest())
+ // index.update(symbols);
+ // }
+ //
+ // This is still technically racy: we could return true here, then another
+ // thread could add->index->update a better library before we can update.
+ // We'd then overwrite it with the older version.
+ // However, it's very unlikely: indexing takes a long time.
+ bool isBest(const LangOptions &) const;
+};
+
+/// Generate a index of the standard library index for a given variant of
+/// the standard library. This index can be included if the translation unit
+/// does not (yet) contain any standard library headers.
+SymbolSlab indexStandardLibrary(std::unique_ptr<CompilerInvocation> Invocation,
+ const StdLibLocation &Loc,
+ const ThreadsafeFS &TFS);
+
+/// Index the given umbrella header file using the standard library from the
+/// given file system.
+SymbolSlab indexUmbrellaHeaders(llvm::StringRef HeaderSources,
+ std::unique_ptr<CompilerInvocation> CI,
+ const StdLibLocation &Loc,
+ const ThreadsafeFS &TFS);
+
+/// generate header containing #includes for all standard library headers
+llvm::StringRef generateUmbrellaHeaders(LangStandard::Kind LibraryVariant);
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_STDLIB_H
Index: clang-tools-extra/clangd/index/StdLib.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/index/StdLib.cpp
@@ -0,0 +1,365 @@
+//===-- StdLib.cpp ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "StdLib.h"
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "Compiler.h"
+#include "Config.h"
+#include "SymbolCollector.h"
+#include "index/IndexAction.h"
+#include "support/Logger.h"
+#include "support/ThreadsafeFS.h"
+#include "support/Trace.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+enum Lang { C, CXX };
+
+llvm::StringLiteral mandatoryHeader(Lang L) {
+ switch (L) {
+ case C:
+ return "stdio.h";
+ case CXX:
+ return "vector";
+ }
+ return L == CXX ? llvm::StringLiteral("vector") : "stdio.h";
+}
+
+std::string buildUmbrella(llvm::StringLiteral Mandatory,
+ std::vector<llvm::StringLiteral> Headers) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+
+ // We __has_include guard all our #includes to avoid errors when using older
+ // stdlib version that don't have headers for the newest language standards.
+ // But make sure we get *some* error if things are totally broken.
+ OS << llvm::formatv(
+ "#if !__has_include(<{0}>)\n"
+ "#error Mandatory header <{0}> not found in standard library!\n"
+ "#endif\n",
+ Mandatory);
+
+ llvm::sort(Headers.begin(), Headers.end());
+ auto Last = std::unique(Headers.begin(), Headers.end());
+ for (auto Header = Headers.begin(); Header != Last; ++Header) {
+ OS << llvm::formatv("#if __has_include({0})\n"
+ "#include {0}\n"
+ "#endif\n",
+ *Header);
+ }
+ OS.flush();
+ return Result;
+}
+
+} // namespace
+
+// Build umbrella header for the the standard library.
+//
+// The umbrella header is the same for all versions of each language.
+// Headers that are unsupported in old lang versions are usually guarded by #if.
+// Some headers may be not present in old stdlib versions, the umbrella header
+// guards with __has_include for this purpose.
+llvm::StringRef generateUmbrellaHeaders(Lang L) {
+ switch (L) {
+ case CXX:
+ static std::string *UmbrellaCXX =
+ new std::string(buildUmbrella(mandatoryHeader(L), {
+#define SYMBOL(Name, NameSpace, Header) #Header,
+#include "StdSymbolMap.inc"
+#undef SYMBOL
+ }));
+ return *UmbrellaCXX;
+ case C:
+ static std::string *UmbrellaC =
+ new std::string(buildUmbrella(mandatoryHeader(L), {
+#define SYMBOL(Name, NameSpace, Header) #Header,
+#include "CSymbolMap.inc"
+#undef SYMBOL
+ }));
+ return *UmbrellaC;
+ }
+}
+
+namespace {
+
+// Including the standard library leaks a lot of symbols/names that are not
+// part of its interface, and we want to drop these. There are two main groups:
+//
+// Implementation details. These tend to have reserved names like __foo.
+// We drop symbols with reserved names unless they're on our symbol list.
+//
+// Transitive includes that are not part of the stdlib (low-level platform deps)
+// These are surprisingly tricky to identify:
+// - we don't want to limit to symbols our our list, as our list has only
+// top-level symbols (and there may be legitimate stdlib extensions).
+// - we can't limit to only symbols defined by known stdlib headers, as stdlib
+// internal structure is murky
+// - we can't strictly require symbols to come from a particular path, e.g.
+// libstdc++ is mostly under /usr/include/c++/10/...
+// but std::ctype_base is under /usr/include/<platform>/c++/10/...
+// Instead we require the symbol to come from a header that is *either* from
+// the standard library path (as identified by the location of <vector>), or
+// another header that defines a symbol from our stdlib list.
+static SymbolSlab filter(SymbolSlab Slab, const StdLibLocation &Loc,
+ llvm::StringRef TUPath) {
+ SymbolSlab::Builder Result;
+
+ static auto &StandardHeaders = *[] {
+ auto Set = new llvm::DenseSet<llvm::StringRef>();
+ for (llvm::StringRef Name : {
+#define SYMBOL(Name, NameSpace, Header) #Header,
+#include "CSymbolMap.inc"
+#include "StdSymbolMap.inc"
+#undef SYMBOL
+ })
+ Set->insert(Name);
+ return Set;
+ }();
+
+ // Form prefixes like file:///usr/include/c++/10/
+ // These can be trivially prefix-compared with URIs in the indexed symbols.
+ llvm::SmallVector<std::string> StdLibURIPrefixes;
+ for (const auto &Path : Loc.Paths) {
+ StdLibURIPrefixes.push_back(URI::create(Path).toString());
+ if (StdLibURIPrefixes.back().back() != '/')
+ StdLibURIPrefixes.back().push_back('/');
+ }
+ // For each header URI, is it *either* prefixed by StdLibURIPrefixes *or*
+ // owner of a symbol whose insertable header is in StandardHeaders?
+ // Pointer key because strings in a SymbolSlab are interned.
+ llvm::DenseMap<const char *, bool> GoodHeader;
+ for (const Symbol &S : Slab) {
+ if (!S.IncludeHeaders.empty() &&
+ StandardHeaders.contains(S.IncludeHeaders.front().IncludeHeader)) {
+ GoodHeader[S.CanonicalDeclaration.FileURI] = true;
+ GoodHeader[S.Definition.FileURI] = true;
+ continue;
+ }
+ for (const char *URI :
+ {S.CanonicalDeclaration.FileURI, S.Definition.FileURI}) {
+ auto R = GoodHeader.try_emplace(URI, false);
+ if (R.second) {
+ R.first->second = llvm::any_of(
+ StdLibURIPrefixes,
+ [&, URIStr(llvm::StringRef(URI))](const std::string &Prefix) {
+ return URIStr.startswith(Prefix);
+ });
+ }
+ }
+ }
+ for (const auto &Good : GoodHeader)
+ if (Good.second)
+ dlog("Stdlib header: {0}", Good.first);
+ // Empty URIs aren't considered good. (Definition can be blank).
+ auto IsGoodHeader = [&](const char *C) { return *C && GoodHeader.lookup(C); };
+
+ for (const Symbol &S : Slab) {
+ if (!(IsGoodHeader(S.CanonicalDeclaration.FileURI) ||
+ IsGoodHeader(S.Definition.FileURI))) {
+ dlog("Ignoring wrong-header symbol {0}{1} in {2}", S.Scope, S.Name,
+ S.CanonicalDeclaration.FileURI);
+ continue;
+ }
+ Result.insert(S);
+ }
+
+ return std::move(Result).build();
+}
+
+LangStandard::Kind standardFromOpts(const LangOptions &LO) {
+ if (LO.CPlusPlus) {
+ return !LO.CPlusPlus11 ? LangStandard::lang_cxx98
+ : !LO.CPlusPlus14 ? LangStandard::lang_cxx11
+ : !LO.CPlusPlus17 ? LangStandard::lang_cxx14
+ : !LO.CPlusPlus20 ? LangStandard::lang_cxx17
+ : !LO.CPlusPlus2b ? LangStandard::lang_cxx20
+ : LangStandard::lang_cxx2b;
+ }
+ return !LO.C11 ? LangStandard::lang_c99
+ // C17 has no new features, so treat C14 as C17.
+ : !LO.C2x ? LangStandard::lang_c17
+ : LangStandard::lang_c2x;
+}
+
+Lang langFromOpts(const LangOptions &LO) { return LO.CPlusPlus ? CXX : C; }
+
+} // namespace
+
+SymbolSlab indexUmbrellaHeaders(llvm::StringRef HeaderSources,
+ std::unique_ptr<CompilerInvocation> CI,
+ const StdLibLocation &Loc,
+ const ThreadsafeFS &TFS) {
+ if (CI->getFrontendOpts().Inputs.size() != 1 ||
+ !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ elog("Indexing standard library failed: bad CompilerInvocation");
+ assert(false && "indexing stdlib with a dubious CompilerInvocation!");
+ return SymbolSlab();
+ }
+ const FrontendInputFile &Input = CI->getFrontendOpts().Inputs.front();
+ trace::Span Tracer("StandardLibraryIndex");
+ LangStandard::Kind LangStd = standardFromOpts(*CI->getLangOpts());
+ log("Indexing {0} standard library in the context of {1}",
+ LangStandard::getLangStandardForKind(LangStd).getName(), Input.getFile());
+
+ SymbolSlab Symbols;
+ IgnoreDiagnostics IgnoreDiags;
+ CI->getPreprocessorOpts().clearRemappedFiles();
+ auto Clang = prepareCompilerInstance(
+ std::move(CI), /*Preamble=*/nullptr,
+ llvm::MemoryBuffer::getMemBuffer(HeaderSources, Input.getFile()),
+ TFS.view(/*CWD=*/llvm::None), IgnoreDiags);
+ if (!Clang) {
+ elog("Standard Library Index: Couldn't build compiler instance");
+ return Symbols;
+ }
+
+ SymbolCollector::Options IndexOpts;
+ IndexOpts.Origin = SymbolOrigin::StdLib;
+ IndexOpts.CollectMainFileSymbols = false;
+ IndexOpts.CollectMainFileRefs = false;
+ IndexOpts.CollectMacro = true;
+ IndexOpts.StoreAllDocumentation = true;
+ // Sadly we can't use IndexOpts.FileFilter to restrict indexing scope.
+ // Files from outside the location may define true std symbols anyway.
+ // We end up "blessing" such headers, and can only do that by indexing
+ // everything first.
+
+ // we only care about the symbols, so not storing the other attributes
+ auto Action = createStaticIndexingAction(
+ IndexOpts, [&](SymbolSlab S) { Symbols = std::move(S); }, nullptr,
+ nullptr, nullptr);
+
+ if (!Action->BeginSourceFile(*Clang, Input)) {
+ elog("Standard Library Index: BeginSourceFile() failed");
+ return Symbols;
+ }
+
+ if (llvm::Error Err = Action->Execute()) {
+ elog("Standard Library Index: Execute failed: {0}", std::move(Err));
+ return Symbols;
+ }
+
+ Action->EndSourceFile();
+ bool HadErrors = Clang->hasDiagnostics() &&
+ Clang->getDiagnostics().hasUncompilableErrorOccurred();
+ if (HadErrors) {
+ log("Errors when generating the standard library index, index may be "
+ "incomplete");
+ }
+
+ unsigned SymbolsBeforeFilter = Symbols.size();
+ Symbols = filter(std::move(Symbols), Loc, Input.getFile());
+ log("Indexed {0} standard library: ({1} symbols, {2} filtered)",
+ LangStandard::getLangStandardForKind(LangStd).getName(), Symbols.size(),
+ SymbolsBeforeFilter - Symbols.size());
+ SPAN_ATTACH(Tracer, "symbols", int(Symbols.size()));
+ return Symbols;
+}
+
+SymbolSlab indexStandardLibrary(std::unique_ptr<CompilerInvocation> Invocation,
+ const StdLibLocation &Loc,
+ const ThreadsafeFS &TFS) {
+ return indexUmbrellaHeaders(
+ generateUmbrellaHeaders(langFromOpts(*Invocation->getLangOpts())),
+ std::move(Invocation), Loc, TFS);
+}
+
+bool StdLibSet::isBest(const LangOptions &LO) const {
+ return standardFromOpts(LO) >=
+ Best[langFromOpts(LO)].load(std::memory_order_acquire);
+}
+
+llvm::Optional<StdLibLocation> StdLibSet::add(const LangOptions &LO,
+ const HeaderSearch &HS) {
+ Lang L = langFromOpts(LO);
+ int OldVersion = Best[L].load(std::memory_order_acquire);
+ int NewVersion = standardFromOpts(LO);
+ dlog("Index stdlib? {0}",
+ LangStandard::getLangStandardForKind(standardFromOpts(LO)).getName());
+
+ if (NewVersion <= OldVersion) {
+ dlog("No: have {0}, {1}>={2}",
+ LangStandard::getLangStandardForKind(
+ static_cast<LangStandard::Kind>(NewVersion))
+ .getName(),
+ OldVersion, NewVersion);
+ return llvm::None;
+ }
+
+ if (!Config::current().Index.StandardLibrary) {
+ dlog("No: disabled in config");
+ return llvm::None;
+ }
+
+ // We'd like to index a standard library here if there is one.
+ // Check for the existence of <vector> on the search path.
+ // We could cache this, but we only get here repeatedly when there's no
+ // stdlib, and even then only once per preamble build.
+ llvm::StringLiteral ProbeHeader = mandatoryHeader(L);
+ llvm::SmallString<256> Path; // Scratch space.
+ llvm::SmallVector<std::string> SearchPaths;
+ auto RecordHeaderPath = [&](llvm::StringRef HeaderPath) {
+ llvm::StringRef DirPath = llvm::sys::path::parent_path(HeaderPath);
+ if (!HS.getFileMgr().getVirtualFileSystem().getRealPath(DirPath, Path))
+ SearchPaths.emplace_back(Path);
+ };
+ for (const auto &DL :
+ llvm::make_range(HS.search_dir_begin(), HS.search_dir_end())) {
+ switch (DL.getLookupType()) {
+ case DirectoryLookup::LT_NormalDir: {
+ Path = DL.getDir()->getName();
+ llvm::sys::path::append(Path, ProbeHeader);
+ llvm::vfs::Status Stat;
+ if (!HS.getFileMgr().getNoncachedStatValue(Path, Stat) &&
+ Stat.isRegularFile())
+ RecordHeaderPath(Path);
+ break;
+ }
+ case DirectoryLookup::LT_Framework:
+ // stdlib can't be a framework (framework includes bust have a slash)
+ continue;
+ case DirectoryLookup::LT_HeaderMap:
+ llvm::StringRef Target =
+ DL.getHeaderMap()->lookupFilename(ProbeHeader, Path);
+ if (!Target.empty())
+ RecordHeaderPath(Target);
+ break;
+ }
+ }
+ if (SearchPaths.empty()) {
+ dlog("No: didn't find <{0}>)", ProbeHeader);
+ return llvm::None;
+ }
+ dlog("Found standard library in {0}", llvm::join(SearchPaths, ", "));
+
+ while (!Best[L].compare_exchange_weak(OldVersion, NewVersion,
+ std::memory_order_acq_rel))
+ if (OldVersion >= NewVersion) {
+ dlog("No: lost the race");
+ return llvm::None; // Another thread won the race while we were checking.
+ }
+
+ dlog("Yes, index stdlib!");
+ return StdLibLocation{std::move(SearchPaths)};
+}
+
+} // namespace clangd
+} // namespace clang
Index: clang-tools-extra/clangd/index/FileIndex.h
===================================================================
--- clang-tools-extra/clangd/index/FileIndex.h
+++ clang-tools-extra/clangd/index/FileIndex.h
@@ -118,6 +118,8 @@
std::shared_ptr<Preprocessor> PP,
const CanonicalIncludes &Includes);
+ void updatePreamble(IndexFileIn);
+
/// Update symbols and references from main file \p Path with
/// `indexMainDecls`.
void updateMain(PathRef Path, ParsedAST &AST);
Index: clang-tools-extra/clangd/index/FileIndex.cpp
===================================================================
--- clang-tools-extra/clangd/index/FileIndex.cpp
+++ clang-tools-extra/clangd/index/FileIndex.cpp
@@ -49,13 +49,15 @@
llvm::ArrayRef<Decl *> DeclsToIndex,
const MainFileMacros *MacroRefsToIndex,
const CanonicalIncludes &Includes, bool IsIndexMainAST,
- llvm::StringRef Version, bool CollectMainFileRefs) {
+ llvm::StringRef Version) {
SymbolCollector::Options CollectorOpts;
CollectorOpts.CollectIncludePath = true;
CollectorOpts.Includes = &Includes;
CollectorOpts.CountReferences = false;
- CollectorOpts.Origin = SymbolOrigin::Dynamic;
- CollectorOpts.CollectMainFileRefs = CollectMainFileRefs;
+ CollectorOpts.Origin =
+ IsIndexMainAST ? SymbolOrigin::Open : SymbolOrigin::Preamble;
+ CollectorOpts.CollectMainFileRefs = IsIndexMainAST;
+ CollectorOpts.CollectReservedSymbols = IsIndexMainAST;
index::IndexingOptions IndexOpts;
// We only need declarations, because we don't count references.
@@ -218,10 +220,10 @@
}
SlabTuple indexMainDecls(ParsedAST &AST) {
- return indexSymbols(
- AST.getASTContext(), AST.getPreprocessorPtr(),
- AST.getLocalTopLevelDecls(), &AST.getMacros(), AST.getCanonicalIncludes(),
- /*IsIndexMainAST=*/true, AST.version(), /*CollectMainFileRefs=*/true);
+ return indexSymbols(AST.getASTContext(), AST.getPreprocessorPtr(),
+ AST.getLocalTopLevelDecls(), &AST.getMacros(),
+ AST.getCanonicalIncludes(),
+ /*IsIndexMainAST=*/true, AST.version());
}
SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
@@ -232,8 +234,7 @@
AST.getTranslationUnitDecl()->decls().end());
return indexSymbols(AST, std::move(PP), DeclsToIndex,
/*MainFileMacros=*/nullptr, Includes,
- /*IsIndexMainAST=*/false, Version,
- /*CollectMainFileRefs=*/false);
+ /*IsIndexMainAST=*/false, Version);
}
FileSymbols::FileSymbols(IndexContents IdxContents)
@@ -423,13 +424,7 @@
MainFileSymbols(IndexContents::All),
MainFileIndex(std::make_unique<MemIndex>()) {}
-void FileIndex::updatePreamble(PathRef Path, llvm::StringRef Version,
- ASTContext &AST,
- std::shared_ptr<Preprocessor> PP,
- const CanonicalIncludes &Includes) {
- IndexFileIn IF;
- std::tie(IF.Symbols, std::ignore, IF.Relations) =
- indexHeaderSymbols(Version, AST, std::move(PP), Includes);
+void FileIndex::updatePreamble(IndexFileIn IF) {
FileShardedIndex ShardedIndex(std::move(IF));
for (auto Uri : ShardedIndex.getAllSources()) {
auto IF = ShardedIndex.getShard(Uri);
@@ -460,6 +455,16 @@
}
}
+void FileIndex::updatePreamble(PathRef Path, llvm::StringRef Version,
+ ASTContext &AST,
+ std::shared_ptr<Preprocessor> PP,
+ const CanonicalIncludes &Includes) {
+ IndexFileIn IF;
+ std::tie(IF.Symbols, std::ignore, IF.Relations) =
+ indexHeaderSymbols(Version, AST, std::move(PP), Includes);
+ updatePreamble(std::move(IF));
+}
+
void FileIndex::updateMain(PathRef Path, ParsedAST &AST) {
auto Contents = indexMainDecls(AST);
MainFileSymbols.update(
Index: clang-tools-extra/clangd/index/Background.cpp
===================================================================
--- clang-tools-extra/clangd/index/Background.cpp
+++ clang-tools-extra/clangd/index/Background.cpp
@@ -285,6 +285,7 @@
return error("Couldn't build compiler instance");
SymbolCollector::Options IndexOpts;
+ IndexOpts.Origin = SymbolOrigin::Background;
// Creates a filter to not collect index results from files with unchanged
// digests.
IndexOpts.FileFilter = [&ShardVersionsSnapshot](const SourceManager &SM,
Index: clang-tools-extra/clangd/TUScheduler.h
===================================================================
--- clang-tools-extra/clangd/TUScheduler.h
+++ clang-tools-extra/clangd/TUScheduler.h
@@ -134,7 +134,7 @@
/// contains only AST nodes from the #include directives at the start of the
/// file. AST node in the current file should be observed on onMainAST call.
virtual void onPreambleAST(PathRef Path, llvm::StringRef Version,
- ASTContext &Ctx,
+ const CompilerInvocation &CI, ASTContext &Ctx,
std::shared_ptr<clang::Preprocessor> PP,
const CanonicalIncludes &) {}
Index: clang-tools-extra/clangd/TUScheduler.cpp
===================================================================
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -977,11 +977,10 @@
LatestBuild = clang::clangd::buildPreamble(
FileName, *Req.CI, Inputs, StoreInMemory,
- [this, Version(Inputs.Version)](ASTContext &Ctx,
- std::shared_ptr<clang::Preprocessor> PP,
- const CanonicalIncludes &CanonIncludes) {
- Callbacks.onPreambleAST(FileName, Version, Ctx, std::move(PP),
- CanonIncludes);
+ [&](ASTContext &Ctx, std::shared_ptr<clang::Preprocessor> PP,
+ const CanonicalIncludes &CanonIncludes) {
+ Callbacks.onPreambleAST(FileName, Inputs.Version, *Req.CI, Ctx,
+ std::move(PP), CanonIncludes);
});
if (LatestBuild && isReliable(LatestBuild->CompileCommand))
HeaderIncluders.update(FileName, LatestBuild->Includes.allHeaders());
Index: clang-tools-extra/clangd/SourceCode.h
===================================================================
--- clang-tools-extra/clangd/SourceCode.h
+++ clang-tools-extra/clangd/SourceCode.h
@@ -16,6 +16,7 @@
#include "Protocol.h"
#include "support/Context.h"
#include "support/ThreadsafeFS.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
@@ -330,6 +331,13 @@
bool isSelfContainedHeader(const FileEntry *FE, FileID ID,
const SourceManager &SM, HeaderSearch &HeaderInfo);
+/// Whether a name is reserved for the implementation, e.g. __Vector_base
+/// Not exhaustive, may return false for some reserved names!
+inline bool isReservedIdentifier(llvm::StringRef N) {
+ // There are other classes of reserved identifiers, but this is common.
+ return N.size() >= 2 && N[0] == '_' && (isUppercase(N[1]) || N[1] == '_');
+}
+
} // namespace clangd
} // namespace clang
#endif
Index: clang-tools-extra/clangd/FS.h
===================================================================
--- clang-tools-extra/clangd/FS.h
+++ clang-tools-extra/clangd/FS.h
@@ -74,6 +74,10 @@
/// filtering everything we get over LSP, CDB, etc.
Path removeDots(PathRef File);
+/// Get a virtual root directory for the filesystem depending on the OS
+/// This is useful when a plausible absolute path name is needed.
+const llvm::StringLiteral virtualRoot();
+
} // namespace clangd
} // namespace clang
Index: clang-tools-extra/clangd/FS.cpp
===================================================================
--- clang-tools-extra/clangd/FS.cpp
+++ clang-tools-extra/clangd/FS.cpp
@@ -117,5 +117,15 @@
return CanonPath.str().str();
}
+const llvm::StringLiteral virtualRoot() {
+#ifdef _WIN32
+ return "C:\\virtual\\";
+#else
+ // This path must exist on the current file system. The only place we can
+ // safely assume to exist is "/".
+ return "/";
+#endif
+}
+
} // namespace clangd
} // namespace clang
Index: clang-tools-extra/clangd/ConfigYAML.cpp
===================================================================
--- clang-tools-extra/clangd/ConfigYAML.cpp
+++ clang-tools-extra/clangd/ConfigYAML.cpp
@@ -167,6 +167,10 @@
F.External.emplace(std::move(External));
F.External->Range = N.getSourceRange();
});
+ Dict.handle("StandardLibrary", [&](Node &N) {
+ if (auto StandardLibrary = boolValue(N, "StandardLibrary"))
+ F.StandardLibrary = *StandardLibrary;
+ });
Dict.parse(N);
}
@@ -194,12 +198,8 @@
void parse(Fragment::CompletionBlock &F, Node &N) {
DictParser Dict("Completion", this);
Dict.handle("AllScopes", [&](Node &N) {
- if (auto Value = scalarValue(N, "AllScopes")) {
- if (auto AllScopes = llvm::yaml::parseBool(**Value))
- F.AllScopes = *AllScopes;
- else
- warning("AllScopes should be a boolean", N);
- }
+ if (auto AllScopes = boolValue(N, "AllScopes"))
+ F.AllScopes = *AllScopes;
});
Dict.parse(N);
}
@@ -334,6 +334,16 @@
return Result;
}
+ llvm::Optional<Located<bool>> boolValue(Node &N, llvm::StringRef Desc) {
+ if (auto Scalar = scalarValue(N, Desc)) {
+ if (auto StandardLibrary = llvm::yaml::parseBool(**Scalar))
+ return Located<bool>(*StandardLibrary, Scalar->Range);
+ else
+ warning(Desc + " should be a boolean", N);
+ }
+ return llvm::None;
+ }
+
// Report a "hard" error, reflecting a config file that can never be valid.
void error(const llvm::Twine &Msg, llvm::SMRange Range) {
HadError = true;
Index: clang-tools-extra/clangd/ConfigFragment.h
===================================================================
--- clang-tools-extra/clangd/ConfigFragment.h
+++ clang-tools-extra/clangd/ConfigFragment.h
@@ -191,6 +191,9 @@
llvm::Optional<Located<std::string>> MountPoint;
};
llvm::Optional<Located<ExternalBlock>> External;
+ // Whether the standard library visible from this file should be indexed.
+ // This makes all standard library symbols available, included or not.
+ llvm::Optional<Located<bool>> StandardLibrary;
};
IndexBlock Index;
Index: clang-tools-extra/clangd/ConfigCompile.cpp
===================================================================
--- clang-tools-extra/clangd/ConfigCompile.cpp
+++ clang-tools-extra/clangd/ConfigCompile.cpp
@@ -321,6 +321,11 @@
}
if (F.External)
compile(std::move(**F.External), F.External->Range);
+ if (F.StandardLibrary)
+ Out.Apply.push_back(
+ [Val(**F.StandardLibrary)](const Params &, Config &C) {
+ C.Index.StandardLibrary = Val;
+ });
}
void compile(Fragment::IndexBlock::ExternalBlock &&External,
Index: clang-tools-extra/clangd/Config.h
===================================================================
--- clang-tools-extra/clangd/Config.h
+++ clang-tools-extra/clangd/Config.h
@@ -79,11 +79,12 @@
/// forward-slashes.
std::string MountPoint;
};
- /// Controls background-index behavior.
+ /// Controls index behavior.
struct {
- /// Whether this TU should be indexed.
+ /// Whether this TU should be background-indexed.
BackgroundPolicy Background = BackgroundPolicy::Build;
ExternalIndexSpec External;
+ bool StandardLibrary = false;
} Index;
enum UnusedIncludesPolicy { Strict, None };
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -14,7 +14,6 @@
#include "FindSymbols.h"
#include "Format.h"
#include "HeaderSourceSwitch.h"
-#include "Headers.h"
#include "InlayHints.h"
#include "ParsedAST.h"
#include "Preamble.h"
@@ -27,10 +26,10 @@
#include "index/CanonicalIncludes.h"
#include "index/FileIndex.h"
#include "index/Merge.h"
+#include "index/StdLib.h"
#include "refactor/Rename.h"
#include "refactor/Tweak.h"
#include "support/Logger.h"
-#include "support/Markup.h"
#include "support/MemoryTree.h"
#include "support/ThreadsafeFS.h"
#include "support/Trace.h"
@@ -43,14 +42,9 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <chrono>
@@ -59,6 +53,7 @@
#include <mutex>
#include <string>
#include <type_traits>
+#include <unordered_set>
namespace clang {
namespace clangd {
@@ -67,16 +62,39 @@
// Update the FileIndex with new ASTs and plumb the diagnostics responses.
struct UpdateIndexCallbacks : public ParsingCallbacks {
UpdateIndexCallbacks(FileIndex *FIndex,
- ClangdServer::Callbacks *ServerCallbacks)
- : FIndex(FIndex), ServerCallbacks(ServerCallbacks) {}
+ ClangdServer::Callbacks *ServerCallbacks,
+ const ThreadsafeFS &TFS, bool Sync)
+ : FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS) {
+ if (!Sync)
+ Tasks.emplace();
+ }
- void onPreambleAST(PathRef Path, llvm::StringRef Version, ASTContext &Ctx,
+ void onPreambleAST(PathRef Path, llvm::StringRef Version,
+ const CompilerInvocation &CI, ASTContext &Ctx,
std::shared_ptr<clang::Preprocessor> PP,
const CanonicalIncludes &CanonIncludes) override {
+ // If this preamble uses a standard library we haven't seen yet, index it.
+ if (auto Loc = Stdlib.add(*CI.getLangOpts(), PP->getHeaderSearchInfo()))
+ indexStdlib(CI, std::move(*Loc));
+
if (FIndex)
FIndex->updatePreamble(Path, Version, Ctx, std::move(PP), CanonIncludes);
}
+ void indexStdlib(const CompilerInvocation &CI, StdLibLocation Loc) {
+ auto Task = [this, LO(*CI.getLangOpts()), Loc(std::move(Loc)),
+ CI(std::make_unique<CompilerInvocation>(CI))]() mutable {
+ IndexFileIn IF;
+ IF.Symbols = indexStandardLibrary(std::move(CI), Loc, TFS);
+ if (Stdlib.isBest(LO))
+ FIndex->updatePreamble(std::move(IF));
+ };
+ if (Tasks)
+ Tasks->runAsync("IndexStdlib", std::move(Task));
+ else
+ Task();
+ }
+
void onMainAST(PathRef Path, ParsedAST &AST, PublishFn Publish) override {
if (FIndex)
FIndex->updateMain(Path, AST);
@@ -111,6 +129,9 @@
private:
FileIndex *FIndex;
ClangdServer::Callbacks *ServerCallbacks;
+ const ThreadsafeFS &TFS;
+ StdLibSet Stdlib;
+ llvm::Optional<AsyncTaskRunner> Tasks;
};
class DraftStoreFS : public ThreadsafeFS {
@@ -163,9 +184,10 @@
// Pass a callback into `WorkScheduler` to extract symbols from a newly
// parsed file and rebuild the file index synchronously each time an AST
// is parsed.
- WorkScheduler.emplace(
- CDB, TUScheduler::Options(Opts),
- std::make_unique<UpdateIndexCallbacks>(DynamicIdx.get(), Callbacks));
+ WorkScheduler.emplace(CDB, TUScheduler::Options(Opts),
+ std::make_unique<UpdateIndexCallbacks>(
+ DynamicIdx.get(), Callbacks, TFS,
+ /*Sync=*/Opts.AsyncThreadsCount == 0));
// Adds an index to the stack, at higher priority than existing indexes.
auto AddIndex = [&](SymbolIndex *Idx) {
if (this->Index != nullptr) {
@@ -895,7 +917,7 @@
// It's safe to pass in the TU, as dumpAST() does not
// deserialize the preamble.
auto Node = DynTypedNode::create(
- *Inputs->AST.getASTContext().getTranslationUnitDecl());
+ *Inputs->AST.getASTContext().getTranslationUnitDecl());
return CB(dumpAST(Node, Inputs->AST.getTokens(),
Inputs->AST.getASTContext()));
}
Index: clang-tools-extra/clangd/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/CMakeLists.txt
+++ clang-tools-extra/clangd/CMakeLists.txt
@@ -119,6 +119,7 @@
index/Ref.cpp
index/Relation.cpp
index/Serialization.cpp
+ index/StdLib.cpp
index/Symbol.cpp
index/SymbolCollector.cpp
index/SymbolID.cpp
Index: clang-tools-extra/clangd/AST.h
===================================================================
--- clang-tools-extra/clangd/AST.h
+++ clang-tools-extra/clangd/AST.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
+#include "SourceCode.h"
#include "index/SymbolID.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -36,6 +37,16 @@
/// in code is considered implementation detail.
bool isImplementationDetail(const Decl *D);
+/// True if the decl has a reserved name like __Vector_base.
+inline bool hasReservedName(const NamedDecl &ND) {
+ if (ND.getDeclName().isIdentifier() && isReservedIdentifier(ND.getName()))
+ llvm::errs() << ND.getName() << " dropped\n";
+ return ND.getDeclName().isIdentifier() && isReservedIdentifier(ND.getName());
+}
+/// True if the DeclContext would be specified with a reserved name.
+/// e.g. std::__Vector_base::iterator
+bool hasReservedScopeName(const DeclContext &DC);
+
/// Find the source location of the identifier for \p D.
/// Transforms macro locations to locations spelled inside files. All code
/// that needs locations of declaration names (e.g. the index) should go through
Index: clang-tools-extra/clangd/AST.cpp
===================================================================
--- clang-tools-extra/clangd/AST.cpp
+++ clang-tools-extra/clangd/AST.cpp
@@ -164,6 +164,25 @@
D->getASTContext().getSourceManager());
}
+bool hasReservedScopeName(const DeclContext &DC) {
+ bool IsLocallyReserved = [&] {
+ if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(&DC))
+ if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(&DC)) {
+ if (DC.isTransparentContext())
+ return false;
+ if (NS->isInlineNamespace())
+ return false;
+ return hasReservedName(*ND);
+ }
+ return false;
+ }();
+ if (IsLocallyReserved)
+ return true;
+ if (DC.getParent() == nullptr)
+ return false;
+ return hasReservedScopeName(*DC.getParent());
+}
+
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM) {
auto L = D.getLocation();
if (isSpelledInSource(L, SM))
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits