-
Notifications
You must be signed in to change notification settings - Fork 71
Expand file tree
/
Copy pathcommand.h
More file actions
295 lines (225 loc) · 10.9 KB
/
command.h
File metadata and controls
295 lines (225 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "command/argument_parser.h"
#include "command/search_config.h"
#include "support/object_pool.h"
#include "support/path_pool.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
namespace clice {
struct CommandOptions {
/// Query the compiler driver for additional information, such as system includes and target.
/// When enabled, also replaces the queried resource dir with our own (clang tools must use
/// builtin headers matching their parser version — see clangd's CommandMangler for precedent).
bool query_toolchain = false;
/// Suppress the warning log if failed to query driver info.
/// Set true in unittests to avoid cluttering test output.
bool suppress_logging = false;
/// Extra arguments to remove from the original command line.
llvm::ArrayRef<std::string> remove;
/// Extra arguments to append to the original command line.
llvm::ArrayRef<std::string> append;
};
struct CompilationContext {
/// The working directory of compilation.
llvm::StringRef directory;
/// The compilation arguments.
std::vector<const char*> arguments;
};
/// Shared compiler identity — driver + all semantics-affecting flags.
/// Deduped via ObjectSet so most files share one instance. This directly
/// serves as the toolchain cache key (no re-parsing needed at query time).
struct CanonicalCommand {
/// Driver path followed by semantics-affecting flags (e.g. -std=, -target, -W*).
/// All pointers are interned in StringSet and pointer-stable.
llvm::ArrayRef<const char*> arguments;
friend bool operator==(const CanonicalCommand&, const CanonicalCommand&) = default;
};
/// Per-file compilation entry = shared canonical + per-file user-content patch.
/// Parsed and classified once at CDB load time; no further parsing needed.
struct CompilationInfo {
/// Working directory (interned in StringSet, pointer-stable).
const char* directory = nullptr;
/// Shared canonical command (driver + semantic flags).
object_ptr<CanonicalCommand> canonical = {nullptr};
/// Per-file user-content options: -I, -D, -U, -include, -isystem, -iquote,
/// -idirafter. Pre-rendered as flat arg list with -I paths already absolutized.
llvm::ArrayRef<const char*> patch;
friend bool operator==(const CompilationInfo&, const CompilationInfo&) = default;
};
/// A single entry in the compilation database, stored in a flat sorted vector.
struct CompilationEntry {
/// Interned path ID for the source file (from PathPool).
std::uint32_t file;
/// Parsed compilation info (directory + canonical + patch).
object_ptr<CompilationInfo> info;
};
/// A pending toolchain query, ready to be executed (possibly in parallel).
struct ToolchainQuery {
std::string key;
std::vector<const char*> query_args;
std::string file;
std::string directory;
};
/// Result of a toolchain query, to be injected back into the cache.
struct ToolchainResult {
std::string key;
std::vector<std::string> cc1_args;
};
} // namespace clice
namespace llvm {
template <>
struct DenseMapInfo<clice::CanonicalCommand> {
using T = clice::CanonicalCommand;
inline static T getEmptyKey() {
return T{
llvm::ArrayRef<const char*>(reinterpret_cast<const char**>(~uintptr_t(0)), size_t(0))};
}
inline static T getTombstoneKey() {
return T{llvm::ArrayRef<const char*>(reinterpret_cast<const char**>(~uintptr_t(0) - 1),
size_t(0))};
}
static unsigned getHashValue(const T& cmd) {
return llvm::hash_combine_range(cmd.arguments);
}
static bool isEqual(const T& lhs, const T& rhs) {
// Sentinels have distinct data pointers but both have size 0,
// and ArrayRef equality is content-based — so we must compare
// data pointers first to keep sentinels distinguishable.
if(lhs.arguments.data() == rhs.arguments.data())
return lhs.arguments.size() == rhs.arguments.size();
if(lhs.arguments.data() == getEmptyKey().arguments.data() ||
lhs.arguments.data() == getTombstoneKey().arguments.data() ||
rhs.arguments.data() == getEmptyKey().arguments.data() ||
rhs.arguments.data() == getTombstoneKey().arguments.data())
return false;
return lhs == rhs;
}
};
template <>
struct DenseMapInfo<clice::CompilationInfo> {
using T = clice::CompilationInfo;
inline static T getEmptyKey() {
return T{llvm::DenseMapInfo<const char*>::getEmptyKey()};
}
inline static T getTombstoneKey() {
return T{llvm::DenseMapInfo<const char*>::getTombstoneKey()};
}
static unsigned getHashValue(const T& info) {
return llvm::hash_combine(info.directory,
info.canonical.ptr,
llvm::hash_combine_range(info.patch));
}
static bool isEqual(const T& lhs, const T& rhs) {
return lhs == rhs;
}
};
} // namespace llvm
namespace clice {
class CompilationDatabase {
public:
CompilationDatabase();
~CompilationDatabase();
CompilationDatabase(const CompilationDatabase&) = delete;
CompilationDatabase& operator=(const CompilationDatabase&) = delete;
CompilationDatabase(CompilationDatabase&&) = default;
CompilationDatabase& operator=(CompilationDatabase&&) = default;
public:
/// Load (or reload) the compilation database from the given file.
/// Full reload: old entries are replaced, SearchConfig cache is cleared,
/// but toolchain cache survives. Returns the number of entries loaded.
std::size_t load(llvm::StringRef path);
/// Lookup the compilation contexts for a file. A file may have multiple
/// compilation commands (e.g. different build configurations); all are returned.
llvm::SmallVector<CompilationContext> lookup(llvm::StringRef file,
const CommandOptions& options = {});
/// Combined lookup + extract_search_config with internal caching.
SearchConfig lookup_search_config(llvm::StringRef file, const CommandOptions& options = {});
/// Check if SearchConfig cache is populated (non-empty).
bool has_cached_configs() const;
/// Resolve a path_id back to the file path string.
llvm::StringRef resolve_path(std::uint32_t path_id);
/// Intern a file path and return its path_id.
std::uint32_t intern_path(llvm::StringRef path);
/// Check if a file has an explicit entry in the compilation database
/// (as opposed to a synthesized default).
bool has_entry(llvm::StringRef file);
/// All compilation entries (sorted by path_id).
llvm::ArrayRef<CompilationEntry> get_entries() const;
/// Entry for batch pre-warming: file + directory + raw compilation arguments.
struct PendingEntry {
llvm::StringRef file;
llvm::StringRef directory;
llvm::SmallVector<const char*, 32> arguments;
};
/// Get pending toolchain queries for a batch of compilation entries.
/// Returns queries only for cache-miss keys (deduplicated).
std::vector<ToolchainQuery> get_pending_queries(llvm::ArrayRef<PendingEntry> entries);
/// Inject pre-computed toolchain results into the cache. Strings are copied
/// into the internal string pool.
void inject_results(llvm::ArrayRef<ToolchainResult> results);
/// Check if toolchain cache has any entries.
bool has_cached_toolchain() const;
#ifdef CLICE_ENABLE_TEST
void add_command(llvm::StringRef directory,
llvm::StringRef file,
llvm::ArrayRef<const char*> arguments);
void add_command(llvm::StringRef directory, llvm::StringRef file, llvm::StringRef command);
#endif
private:
/// Find all CompilationEntry items for a file by path_id (binary search).
/// Returns a sub-range of `entries`; may be empty.
llvm::ArrayRef<CompilationEntry> find_entries(std::uint32_t path_id) const;
/// Allocate a persistent copy of a const char* array on the bump allocator.
llvm::ArrayRef<const char*> persist_args(llvm::ArrayRef<const char*> args);
/// Parse and classify a compilation command into canonical + patch.
object_ptr<CompilationInfo> save_compilation_info(llvm::StringRef file,
llvm::StringRef directory,
llvm::ArrayRef<const char*> arguments);
object_ptr<CompilationInfo> save_compilation_info(llvm::StringRef file,
llvm::StringRef directory,
llvm::StringRef command);
static std::uint8_t options_bits(const CommandOptions& options) {
return options.query_toolchain ? 1u : 0u;
}
struct ToolchainExtract {
std::string key;
std::vector<const char*> query_args;
};
/// Extract toolchain-relevant flags and build a cache key.
ToolchainExtract extract_toolchain_flags(llvm::StringRef file,
llvm::ArrayRef<const char*> arguments);
/// Query toolchain with caching. Returns cached cc1 args, running the
/// expensive compiler query only on cache miss.
llvm::ArrayRef<const char*> query_toolchain_cached(llvm::StringRef file,
llvm::StringRef directory,
llvm::ArrayRef<const char*> arguments);
/// The memory pool which holds all elements of compilation database.
/// Heap-allocated so its address is stable across moves.
std::unique_ptr<llvm::BumpPtrAllocator> allocator = std::make_unique<llvm::BumpPtrAllocator>();
/// Keep all strings (arguments, directories, etc.).
StringSet strings{allocator.get()};
/// Shared canonical commands — most files share one instance.
ObjectSet<CanonicalCommand> canonicals{allocator.get()};
/// Per-file compilation infos (canonical + patch + directory).
ObjectSet<CompilationInfo> infos{allocator.get()};
/// Intern pool for file paths → compact uint32_t IDs.
PathPool paths;
/// All compilation entries, sorted by file path_id.
/// Multiple entries for the same file are adjacent.
std::vector<CompilationEntry> entries;
/// Cache of SearchConfig keyed by (CompilationInfo*, options_bits).
using ConfigCacheKey = std::pair<const CompilationInfo*, std::uint8_t>;
llvm::DenseMap<ConfigCacheKey, SearchConfig> search_config_cache;
/// Cache of toolchain query results, keyed by canonical toolchain key.
llvm::StringMap<std::vector<const char*>> toolchain_cache;
std::unique_ptr<ArgumentParser> parser = std::make_unique<ArgumentParser>(allocator.get());
};
} // namespace clice