1 | //===--- StdLib.h - Index the C and C++ standard library ---------*- C++-*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // Eagerly indexing the standard library gives a much friendlier "warm start" |
9 | // with working code completion in a standalone file or small project. |
10 | // |
11 | // We act as if we saw a file which included the whole standard library: |
12 | // #include <array> |
13 | // #include <bitset> |
14 | // #include <chrono> |
15 | // ... |
16 | // We index this TU and feed the result into the dynamic index. |
17 | // |
18 | // This happens within the context of some particular open file, and we reuse |
19 | // its CompilerInvocation. Matching its include path, LangOpts etc ensures that |
20 | // we see the standard library and configuration that matches the project. |
21 | //===----------------------------------------------------------------------===// |
22 | |
23 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_STDLIB_H |
24 | #define |
25 | |
26 | #include "index/Symbol.h" |
27 | #include "support/ThreadsafeFS.h" |
28 | #include "llvm/ADT/StringRef.h" |
29 | #include <optional> |
30 | #include <string> |
31 | |
32 | namespace clang { |
33 | class CompilerInvocation; |
34 | class LangOptions; |
35 | class ; |
36 | namespace clangd { |
37 | |
38 | // The filesystem location where a standard library was found. |
39 | // |
40 | // This is the directory containing <vector> or <stdio.h>. |
41 | // It's used to ensure we only index files that are in the standard library. |
42 | // |
43 | // The paths are canonicalized (FS "real path" with symlinks resolved). |
44 | // This allows them to be easily compared against paths the indexer returns. |
45 | struct StdLibLocation { |
46 | llvm::SmallVector<std::string> Paths; |
47 | }; |
48 | |
49 | // Tracks the state of standard library indexing within a particular index. |
50 | // |
51 | // In general, we don't want to index the standard library multiple times. |
52 | // In most cases, this class just acts as a flag to ensure we only do it once. |
53 | // |
54 | // However, if we first open a C++11 file, and then a C++20 file, we *do* |
55 | // want the index to be upgraded to include the extra symbols. |
56 | // Similarly, the C and C++ standard library can coexist. |
57 | class StdLibSet { |
58 | std::atomic<int> Best[2] = {{-1}, {-1}}; |
59 | |
60 | public: |
61 | // Determines if we should index the standard library in a configuration. |
62 | // |
63 | // This is true if: |
64 | // - standard library indexing is enabled for the file |
65 | // - the language version is higher than any previous add() for the language |
66 | // - the standard library headers exist on the search path |
67 | // Returns the location where the standard library was found. |
68 | // |
69 | // This function is threadsafe. |
70 | std::optional<StdLibLocation> (const LangOptions &, const HeaderSearch &); |
71 | |
72 | // Indicates whether a built index should be used. |
73 | // It should not be used if a newer version has subsequently been added. |
74 | // |
75 | // Intended pattern is: |
76 | // if (add()) { |
77 | // symbols = indexStandardLibrary(); |
78 | // if (isBest()) |
79 | // index.update(symbols); |
80 | // } |
81 | // |
82 | // This is still technically racy: we could return true here, then another |
83 | // thread could add->index->update a better library before we can update. |
84 | // We'd then overwrite it with the older version. |
85 | // However, it's very unlikely: indexing takes a long time. |
86 | bool isBest(const LangOptions &) const; |
87 | }; |
88 | |
89 | // Index a standard library and return the discovered symbols. |
90 | // |
91 | // The compiler invocation should describe the file whose config we're reusing. |
92 | // We overwrite its virtual buffer with a lot of #include statements. |
93 | SymbolSlab indexStandardLibrary(std::unique_ptr<CompilerInvocation> Invocation, |
94 | const StdLibLocation &Loc, |
95 | const ThreadsafeFS &TFS); |
96 | |
97 | // Variant that allows the umbrella header source to be specified. |
98 | // Exposed for testing. |
99 | SymbolSlab indexStandardLibrary(llvm::StringRef , |
100 | std::unique_ptr<CompilerInvocation> CI, |
101 | const StdLibLocation &Loc, |
102 | const ThreadsafeFS &TFS); |
103 | |
104 | // Generate header containing #includes for all standard library headers. |
105 | // Exposed for testing. |
106 | llvm::StringRef (const LangOptions &); |
107 | |
108 | } // namespace clangd |
109 | } // namespace clang |
110 | |
111 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_STDLIB_H |
112 | |