|
4 | 4 | #include "llvm/ADT/DenseSet.h" |
5 | 5 | #include "llvm/ADT/StringMap.h" |
6 | 6 | #include "llvm/Support/Allocator.h" |
| 7 | +#include "llvm/ADT/ArrayRef.h" |
| 8 | +#include <deque> |
7 | 9 |
|
8 | 10 | namespace clice { |
9 | 11 |
|
10 | | -/// `CompilationDatabase` is responsible for managing the compile commands. |
11 | | -/// |
12 | | -/// FIXME: currently we assume that a file only occurs once in the CDB. |
13 | | -/// This is not always correct, but it is enough for now. |
14 | 12 | class CompilationDatabase { |
15 | 13 | public: |
16 | 14 | using Self = CompilationDatabase; |
17 | 15 |
|
18 | | - /// Update the compile commands with the given file. |
19 | | - void update_commands(this Self& self, llvm::StringRef file); |
| 16 | + enum class UpdateKind : std::uint8_t { |
| 17 | + Unchange, |
| 18 | + Create, |
| 19 | + Update, |
| 20 | + Delete, |
| 21 | + }; |
| 22 | + |
| 23 | + struct CommandInfo { |
| 24 | + /// TODO: add sysroot or no stdinc command info. |
| 25 | + llvm::StringRef dictionary; |
20 | 26 |
|
21 | | - /// Update the module map with the given file and module name. |
22 | | - void update_module(llvm::StringRef file, llvm::StringRef name); |
| 27 | + /// The canonical command list. |
| 28 | + llvm::ArrayRef<const char*> arguments; |
| 29 | + }; |
23 | 30 |
|
24 | | - /// Lookup the module interface unit file path of the given module name. |
25 | | - llvm::StringRef get_module_file(llvm::StringRef name); |
| 31 | + struct DriverInfo { |
| 32 | + /// The target of this driver. |
| 33 | + llvm::StringRef target; |
26 | 34 |
|
27 | | - auto size() const { |
28 | | - return commands.size(); |
29 | | - } |
| 35 | + /// The default system includes of this driver. |
| 36 | + llvm::ArrayRef<const char*> system_includes; |
| 37 | + }; |
| 38 | + |
| 39 | + struct UpdateInfo { |
| 40 | + /// The kind of update. |
| 41 | + UpdateKind kind; |
30 | 42 |
|
31 | | - enum class Style { |
32 | | - GNU = 0, |
33 | | - MSVC, |
| 43 | + llvm::StringRef file; |
34 | 44 | }; |
35 | 45 |
|
36 | | - void add_command(this Self& self, |
37 | | - llvm::StringRef path, |
38 | | - llvm::StringRef command, |
39 | | - Style style = Style::GNU); |
| 46 | + struct LookupInfo { |
| 47 | + llvm::StringRef dictionary; |
40 | 48 |
|
41 | | - llvm::ArrayRef<const char*> get_command(this Self& self, llvm::StringRef path); |
| 49 | + std::vector<const char*> arguments; |
| 50 | + }; |
42 | 51 |
|
43 | | -private: |
44 | | - /// Save a string into memory pool. Make sure end with `\0`. |
45 | | - llvm::StringRef save_string(this Self& self, llvm::StringRef string); |
| 52 | + CompilationDatabase(); |
46 | 53 |
|
47 | | - std::vector<const char*> save_args(this Self& self, llvm::ArrayRef<const char*> args); |
| 54 | + auto save_string(this Self& self, llvm::StringRef string) -> llvm::StringRef; |
| 55 | + |
| 56 | + auto save_cstring_list(this Self& self, llvm::ArrayRef<const char*> arguments) |
| 57 | + -> llvm::ArrayRef<const char*>; |
| 58 | + |
| 59 | + /// Get an the option for specific argument. |
| 60 | + static std::optional<std::uint32_t> get_option_id(llvm::StringRef argument); |
| 61 | + |
| 62 | + /// Query the compiler driver and return its driver info. |
| 63 | + auto query_driver(this Self& self, llvm::StringRef driver) |
| 64 | + -> std::expected<DriverInfo, std::string>; |
| 65 | + |
| 66 | + /// Update with arguments. |
| 67 | + auto update_command(this Self& self, |
| 68 | + llvm::StringRef dictionary, |
| 69 | + llvm::StringRef file, |
| 70 | + llvm::ArrayRef<const char*> arguments) -> UpdateInfo; |
| 71 | + |
| 72 | + /// Update with full command. |
| 73 | + auto update_command(this Self& self, |
| 74 | + llvm::StringRef dictionary, |
| 75 | + llvm::StringRef file, |
| 76 | + llvm::StringRef command) -> UpdateInfo; |
| 77 | + |
| 78 | + /// Update commands from json file and return all updated file. |
| 79 | + auto load_commands(this Self& self, llvm::StringRef json_content) |
| 80 | + -> std::expected<std::vector<UpdateInfo>, std::string>; |
| 81 | + |
| 82 | + auto get_command(this Self& self, llvm::StringRef file, bool resource_dir = false) -> LookupInfo; |
48 | 83 |
|
49 | 84 | private: |
50 | | - /// For C++20 module, we only can got dependent module name |
51 | | - /// in source context. But we need dependent module file path |
52 | | - /// to build PCM. So we will scan(preprocess) all project files |
53 | | - /// to build a module map between module name and module file path. |
54 | | - /// **Note that** this only includes module interface unit, for module |
55 | | - /// implementation unit, the scan could be delayed until compiling it. |
56 | | - llvm::StringMap<std::string> moduleMap; |
57 | | - |
58 | | - /// Memory pool for command arguments. |
59 | | - llvm::BumpPtrAllocator memory_pool; |
60 | | - |
61 | | - /// For lookup whether we already have the key. |
62 | | - llvm::DenseSet<llvm::StringRef> unique; |
63 | | - |
64 | | - // A map between file path and compile commands. |
65 | | - /// TODO: Path cannot represent unique file, we should use better, like inode ... |
66 | | - llvm::DenseMap<const char*, std::unique_ptr<std::vector<const char*>>> commands; |
| 85 | + /// The memory pool to hold all cstring and command list. |
| 86 | + llvm::BumpPtrAllocator allocator; |
| 87 | + |
| 88 | + /// A cache between input string and its cache cstring |
| 89 | + /// in the allocator, make sure end with `\0`. |
| 90 | + llvm::DenseSet<llvm::StringRef> string_cache; |
| 91 | + |
| 92 | + /// A cache between input command and its cache array |
| 93 | + /// in the allocator. |
| 94 | + llvm::DenseSet<llvm::ArrayRef<const char*>> arguments_cache; |
| 95 | + |
| 96 | + /// The clang options we want to filter in all cases, like -c and -o. |
| 97 | + llvm::DenseSet<std::uint32_t> filtered_options; |
| 98 | + |
| 99 | + /// A map between file path and its canonical command list. |
| 100 | + llvm::DenseMap<const void*, CommandInfo> command_infos; |
| 101 | + |
| 102 | + /// A map between driver path and its query driver info. |
| 103 | + llvm::DenseMap<const void*, DriverInfo> driver_infos; |
67 | 104 | }; |
68 | 105 |
|
69 | 106 | } // namespace clice |
70 | 107 |
|
| 108 | +namespace llvm { |
| 109 | + |
| 110 | +template <> |
| 111 | +struct DenseMapInfo<llvm::ArrayRef<const char*>> { |
| 112 | + using T = llvm::ArrayRef<const char*>; |
| 113 | + |
| 114 | + inline static T getEmptyKey() { |
| 115 | + return T(reinterpret_cast<T::const_pointer>(~0), T::size_type(0)); |
| 116 | + } |
| 117 | + |
| 118 | + inline static T getTombstoneKey() { |
| 119 | + return T(reinterpret_cast<T::const_pointer>(~1), T::size_type(0)); |
| 120 | + } |
| 121 | + |
| 122 | + static unsigned getHashValue(const T& value) { |
| 123 | + return llvm::hash_combine_range(value.begin(), value.end()); |
| 124 | + } |
| 125 | + |
| 126 | + static bool isEqual(const T& lhs, const T& rhs) { |
| 127 | + return lhs == rhs; |
| 128 | + } |
| 129 | +}; |
| 130 | + |
| 131 | +} // namespace llvm |
0 commit comments