Skip to content

Commit de75008

Browse files
authored
[clangd] Support -specs arguments when querying the driver. (#70285)
Similarly to commit 3935a29, forward spec file arguments to the driver if they appear in the compile database. Spec files can affect the include search path. fixes clangd/clangd#1410
1 parent 5f5f82a commit de75008

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

clang-tools-extra/clangd/SystemIncludeExtractor.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,14 @@ struct DriverArgs {
8989
std::string ISysroot;
9090
std::string Target;
9191
std::string Stdlib;
92+
llvm::SmallVector<std::string> Specs;
9293

9394
bool operator==(const DriverArgs &RHS) const {
9495
return std::tie(Driver, StandardIncludes, StandardCXXIncludes, Lang,
95-
Sysroot, ISysroot, Target, Stdlib) ==
96+
Sysroot, ISysroot, Target, Stdlib, Specs) ==
9697
std::tie(RHS.Driver, RHS.StandardIncludes, RHS.StandardCXXIncludes,
97-
RHS.Lang, RHS.Sysroot, RHS.ISysroot, RHS.Target,
98-
RHS.Stdlib);
98+
RHS.Lang, RHS.Sysroot, RHS.ISysroot, RHS.Target, RHS.Stdlib,
99+
RHS.Specs);
99100
}
100101

101102
DriverArgs(const tooling::CompileCommand &Cmd, llvm::StringRef File) {
@@ -145,6 +146,17 @@ struct DriverArgs {
145146
Stdlib = Cmd.CommandLine[I + 1];
146147
} else if (Arg.consume_front("-stdlib=")) {
147148
Stdlib = Arg.str();
149+
} else if (Arg.startswith("-specs=")) {
150+
// clang requires a single token like `-specs=file` or `--specs=file`,
151+
// but gcc will accept two tokens like `--specs file`. Since the
152+
// compilation database is presumably correct, we just forward the flags
153+
// as-is.
154+
Specs.push_back(Arg.str());
155+
} else if (Arg.startswith("--specs=")) {
156+
Specs.push_back(Arg.str());
157+
} else if (Arg == "--specs" && I + 1 < E) {
158+
Specs.push_back(Arg.str());
159+
Specs.push_back(Cmd.CommandLine[I + 1]);
148160
}
149161
}
150162

@@ -186,6 +198,11 @@ struct DriverArgs {
186198
Args.append({"-target", Target});
187199
if (!Stdlib.empty())
188200
Args.append({"--stdlib", Stdlib});
201+
202+
for (llvm::StringRef Spec : Specs) {
203+
Args.push_back(Spec);
204+
}
205+
189206
return Args;
190207
}
191208

@@ -210,7 +227,7 @@ template <> struct DenseMapInfo<DriverArgs> {
210227
return Driver;
211228
}
212229
static unsigned getHashValue(const DriverArgs &Val) {
213-
return llvm::hash_value(std::tuple{
230+
unsigned FixedFieldsHash = llvm::hash_value(std::tuple{
214231
Val.Driver,
215232
Val.StandardIncludes,
216233
Val.StandardCXXIncludes,
@@ -220,6 +237,11 @@ template <> struct DenseMapInfo<DriverArgs> {
220237
Val.Target,
221238
Val.Stdlib,
222239
});
240+
241+
unsigned SpecsHash =
242+
llvm::hash_combine_range(Val.Specs.begin(), Val.Specs.end());
243+
244+
return llvm::hash_combine(FixedFieldsHash, SpecsHash);
223245
}
224246
static bool isEqual(const DriverArgs &LHS, const DriverArgs &RHS) {
225247
return LHS == RHS;

clang-tools-extra/clangd/test/system-include-extractor.test

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
# RUN: echo '[ -z "${args##*"-isysroot /isysroot"*}" ] || exit' >> %t.dir/bin/my_driver.sh
2020
# RUN: echo '[ -z "${args##*"-target arm-linux-gnueabihf"*}" ] || exit' >> %t.dir/bin/my_driver.sh
2121
# RUN: echo '[ -z "${args##*"--stdlib libc++"*}" ] || exit' >> %t.dir/bin/my_driver.sh
22+
# RUN: echo '[ -z "${args##*"-specs=test.spec"*}" ] || exit' >> %t.dir/bin/my_driver.sh
23+
# RUN: echo '[ -z "${args##*"--specs=test2.spec"*}" ] || exit' >> %t.dir/bin/my_driver.sh
24+
# Check that clangd drops other flags like -lc++, which don't affect includes
25+
# RUN: echo '[ -n "${args##*"-lc++"*}" ] || exit' >> %t.dir/bin/my_driver.sh
2226
# RUN: echo 'echo line to ignore >&2' >> %t.dir/bin/my_driver.sh
2327
# RUN: echo 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/bin/my_driver.sh
2428
# RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/bin/my_driver.sh
@@ -38,7 +42,7 @@
3842

3943
# Generate a compile_commands.json that will query the mock driver we've
4044
# created. Which should add a.h and b.h into include search path.
41-
# RUN: echo '[{"directory": "%/t.dir", "command": "my_driver.sh the-file.cpp --target=arm-linux-gnueabihf -nostdinc --sysroot /my/sysroot/path -isysroot/isysroot -stdlib=libc++", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
45+
# RUN: echo '[{"directory": "%/t.dir", "command": "my_driver.sh the-file.cpp --target=arm-linux-gnueabihf -nostdinc --sysroot /my/sysroot/path -isysroot/isysroot -stdlib=libc++ -lc++ -specs=test.spec --specs=test2.spec", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
4246

4347
# RUN: sed -e "s|INPUT_DIR|%/t.dir|g" %s > %t.test.1
4448
# On Windows, we need the URI in didOpen to look like "uri":"file:///C:/..."
@@ -76,7 +80,7 @@
7680
{"jsonrpc":"2.0","method":"exit"}
7781

7882
# Generate a different compile_commands.json which does not point to the mock driver
79-
# RUN: echo '[{"directory": "%/t.dir", "command": "gcc the-file.cpp --target=arm-linux-gnueabihf -nostdinc --sysroot /my/sysroot/path -isysroot/isysroot -stdlib=libc++", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
83+
# RUN: echo '[{"directory": "%/t.dir", "command": "gcc the-file.cpp --target=arm-linux-gnueabihf -nostdinc --sysroot /my/sysroot/path -isysroot/isysroot -stdlib=libc++ -lc++ -specs=test.spec --specs=test2.spec", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
8084

8185
# Generate a clangd config file which points to the mock driver instead
8286
# RUN: echo 'CompileFlags:' > %t.dir/.clangd

0 commit comments

Comments
 (0)