Skip to content

[clangd] Support -specs arguments when querying the driver. #70285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 3, 2023

Conversation

cjc25
Copy link
Contributor

@cjc25 cjc25 commented Oct 26, 2023

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

@llvmbot llvmbot added the clangd label Oct 26, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 26, 2023

@llvm/pr-subscribers-clangd

Author: Chris Carlon (cjc25)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/70285.diff

2 Files Affected:

  • (modified) clang-tools-extra/clangd/SystemIncludeExtractor.cpp (+26-4)
  • (modified) clang-tools-extra/clangd/test/system-include-extractor.test (+7-2)
diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
index a86f152c3bf364e..ea98c7d948a2f6d 100644
--- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
+++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
@@ -89,13 +89,14 @@ struct DriverArgs {
   std::string ISysroot;
   std::string Target;
   std::string Stdlib;
+  llvm::SmallVector<std::string> Specs;
 
   bool operator==(const DriverArgs &RHS) const {
     return std::tie(Driver, StandardIncludes, StandardCXXIncludes, Lang,
-                    Sysroot, ISysroot, Target, Stdlib) ==
+                    Sysroot, ISysroot, Target, Stdlib, Specs) ==
            std::tie(RHS.Driver, RHS.StandardIncludes, RHS.StandardCXXIncludes,
-                    RHS.Lang, RHS.Sysroot, RHS.ISysroot, RHS.Target,
-                    RHS.Stdlib);
+                    RHS.Lang, RHS.Sysroot, RHS.ISysroot, RHS.Target, RHS.Stdlib,
+                    RHS.Specs);
   }
 
   DriverArgs(const tooling::CompileCommand &Cmd, llvm::StringRef File) {
@@ -145,6 +146,17 @@ struct DriverArgs {
           Stdlib = Cmd.CommandLine[I + 1];
       } else if (Arg.consume_front("-stdlib=")) {
         Stdlib = Arg.str();
+      } else if (Arg.startswith("-specs=")) {
+        // clang requires a single token like `-specs=file` or `--specs=file`,
+        // but gcc will accept two tokens like `--specs file`. Since the
+        // compilation database is presumably correct, we just forward the flags
+        // as-is.
+        Specs.push_back(Arg.str());
+      } else if (Arg.startswith("--specs=")) {
+        Specs.push_back(Arg.str());
+      } else if (Arg == "--specs" && I + 1 < E) {
+        Specs.push_back(Arg.str());
+        Specs.push_back(Cmd.CommandLine[I + 1]);
       }
     }
 
@@ -186,6 +198,11 @@ struct DriverArgs {
       Args.append({"-target", Target});
     if (!Stdlib.empty())
       Args.append({"--stdlib", Stdlib});
+
+    for (llvm::StringRef Spec : Specs) {
+      Args.push_back(Spec);
+    }
+
     return Args;
   }
 
@@ -210,7 +227,7 @@ template <> struct DenseMapInfo<DriverArgs> {
     return Driver;
   }
   static unsigned getHashValue(const DriverArgs &Val) {
-    return llvm::hash_value(std::tuple{
+    unsigned FixedFieldsHash = llvm::hash_value(std::tuple{
         Val.Driver,
         Val.StandardIncludes,
         Val.StandardCXXIncludes,
@@ -220,6 +237,11 @@ template <> struct DenseMapInfo<DriverArgs> {
         Val.Target,
         Val.Stdlib,
     });
+
+    unsigned SpecsHash =
+        llvm::hash_combine_range(Val.Specs.begin(), Val.Specs.end());
+
+    return llvm::hash_combine(FixedFieldsHash, SpecsHash);
   }
   static bool isEqual(const DriverArgs &LHS, const DriverArgs &RHS) {
     return LHS == RHS;
diff --git a/clang-tools-extra/clangd/test/system-include-extractor.test b/clang-tools-extra/clangd/test/system-include-extractor.test
index cbb3018b2fa7349..4ff6f946ffa73d4 100644
--- a/clang-tools-extra/clangd/test/system-include-extractor.test
+++ b/clang-tools-extra/clangd/test/system-include-extractor.test
@@ -19,6 +19,11 @@
 # RUN: echo '[ -z "${args##*"-isysroot /isysroot"*}" ] || exit' >> %t.dir/bin/my_driver.sh
 # RUN: echo '[ -z "${args##*"-target arm-linux-gnueabihf"*}" ] || exit' >> %t.dir/bin/my_driver.sh
 # RUN: echo '[ -z "${args##*"--stdlib libc++"*}" ] || exit' >> %t.dir/bin/my_driver.sh
+# RUN: echo '[ -z "${args##*"-specs=test.spec"*}" ] || exit' >> %t.dir/bin/my_driver.sh
+# RUN: echo '[ -z "${args##*"--specs=test2.spec"*}" ] || exit' >> %t.dir/bin/my_driver.sh
+# RUN: echo '[ -z "${args##*"--specs test3.spec"*}" ] || exit' >> %t.dir/bin/my_driver.sh
+# Check that clangd drops other flags like -lc++, which don't affect includes
+# RUN: echo '[ -n "${args##*"-lc++"*}" ] || exit' >> %t.dir/bin/my_driver.sh
 # RUN: echo 'echo line to ignore >&2' >> %t.dir/bin/my_driver.sh
 # RUN: echo 'printf "Target: arm-linux-gnueabihf\r\n" >&2' >> %t.dir/bin/my_driver.sh
 # RUN: echo 'printf "#include <...> search starts here:\r\n" >&2' >> %t.dir/bin/my_driver.sh
@@ -38,7 +43,7 @@
 
 # Generate a compile_commands.json that will query the mock driver we've
 # created. Which should add a.h and b.h into include search path.
-# 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
+# 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. --specs=test2.spec --specs test3.spec", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
 
 # RUN: sed -e "s|INPUT_DIR|%/t.dir|g" %s > %t.test.1
 # On Windows, we need the URI in didOpen to look like "uri":"file:///C:/..."
@@ -76,7 +81,7 @@
 {"jsonrpc":"2.0","method":"exit"}
 
 # Generate a different compile_commands.json which does not point to the mock driver
-# 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
+# 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. --specs=test2.spec --specs test3.spec", "file": "the-file.cpp"}]' > %t.dir/compile_commands.json
 
 # Generate a clangd config file which points to the mock driver instead
 # RUN: echo 'CompileFlags:' > %t.dir/.clangd

@cjc25 cjc25 marked this pull request as draft October 27, 2023 12:09
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
Copy link
Collaborator

@HighCommander4 HighCommander4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SystemIncludesExtractor stripping meaningful compiler arguments
3 participants