-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clangd] Fix sysroot flag handling in CommandMangler to prevent duplicates #75694
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
Conversation
@llvm/pr-subscribers-clangd Author: Kon (kon72) ChangesIn CommandMangler, it guesses sysroot path of the host system and adds that through Full diff: https://github.com/llvm/llvm-project/pull/75694.diff 2 Files Affected:
diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp
index f43ce928463b90..a3c6f3f41118e4 100644
--- a/clang-tools-extra/clangd/CompileCommands.cpp
+++ b/clang-tools-extra/clangd/CompileCommands.cpp
@@ -328,13 +328,15 @@ void CommandMangler::operator()(tooling::CompileCommand &Command,
tooling::addTargetAndModeForProgramName(Cmd, Cmd.front());
- // Check whether the flag exists, either as -flag or -flag=*
- auto Has = [&](llvm::StringRef Flag) {
- for (llvm::StringRef Arg : Cmd) {
- if (Arg.consume_front(Flag) && (Arg.empty() || Arg[0] == '='))
- return true;
- }
- return false;
+ // Check whether the flag exists in the command.
+ auto HasExact = [&](llvm::StringRef Flag) {
+ return llvm::any_of(Cmd, [&](llvm::StringRef Arg) { return Arg == Flag; });
+ };
+
+ // Check whether the flag appears in the command as a prefix.
+ auto HasPrefix = [&](llvm::StringRef Flag) {
+ return llvm::any_of(
+ Cmd, [&](llvm::StringRef Arg) { return Arg.startswith(Flag); });
};
llvm::erase_if(Cmd, [](llvm::StringRef Elem) {
@@ -342,12 +344,13 @@ void CommandMangler::operator()(tooling::CompileCommand &Command,
});
std::vector<std::string> ToAppend;
- if (ResourceDir && !Has("-resource-dir"))
+ if (ResourceDir && !HasExact("-resource-dir") && !HasPrefix("-resource-dir="))
ToAppend.push_back(("-resource-dir=" + *ResourceDir));
// Don't set `-isysroot` if it is already set or if `--sysroot` is set.
// `--sysroot` is a superset of the `-isysroot` argument.
- if (Sysroot && !Has("-isysroot") && !Has("--sysroot")) {
+ if (Sysroot && !HasPrefix("-isysroot") && !HasExact("--sysroot") &&
+ !HasPrefix("--sysroot=")) {
ToAppend.push_back("-isysroot");
ToAppend.push_back(*Sysroot);
}
@@ -358,7 +361,7 @@ void CommandMangler::operator()(tooling::CompileCommand &Command,
}
if (!Cmd.empty()) {
- bool FollowSymlink = !Has("-no-canonical-prefixes");
+ bool FollowSymlink = !HasExact("-no-canonical-prefixes");
Cmd.front() =
(FollowSymlink ? ResolvedDrivers : ResolvedDriversNoFollow)
.get(Cmd.front(), [&, this] {
diff --git a/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp b/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
index 28f0d85d332caa..cad135923f71c1 100644
--- a/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
@@ -385,9 +385,8 @@ TEST(ArgStripperTest, OrderDependent) {
}
TEST(PrintArgvTest, All) {
- std::vector<llvm::StringRef> Args = {
- "one", "two", "thr ee", "f\"o\"ur", "fi\\ve", "$"
- };
+ std::vector<llvm::StringRef> Args = {"one", "two", "thr ee",
+ "f\"o\"ur", "fi\\ve", "$"};
const char *Expected = R"(one two "thr ee" "f\"o\"ur" "fi\\ve" $)";
EXPECT_EQ(Expected, printArgv(Args));
}
@@ -465,6 +464,82 @@ TEST(CommandMangler, PathsAsPositional) {
Mangler(Cmd, "a.cc");
EXPECT_THAT(Cmd.CommandLine, Contains("foo"));
}
+
+TEST(CommandMangler, RespectsOriginalResourceDir) {
+ auto Mangler = CommandMangler::forTests();
+ Mangler.ResourceDir = testPath("fake/resources");
+
+ {
+ tooling::CompileCommand Cmd;
+ Cmd.CommandLine = {"clang++", "-resource-dir", testPath("true/resources"),
+ "foo.cc"};
+ Mangler(Cmd, "foo.cc");
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ HasSubstr("-resource-dir " + testPath("true/resources")));
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ Not(HasSubstr(testPath("fake/resources"))));
+ }
+
+ {
+ tooling::CompileCommand Cmd;
+ Cmd.CommandLine = {"clang++", "-resource-dir=" + testPath("true/resources"),
+ "foo.cc"};
+ Mangler(Cmd, "foo.cc");
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ HasSubstr("-resource-dir=" + testPath("true/resources")));
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ Not(HasSubstr(testPath("fake/resources"))));
+ }
+}
+
+TEST(CommandMangler, RespectsOriginalSysroot) {
+ auto Mangler = CommandMangler::forTests();
+ Mangler.Sysroot = testPath("fake/sysroot");
+
+ {
+ tooling::CompileCommand Cmd;
+ Cmd.CommandLine = {"clang++", "-isysroot", testPath("true/sysroot"),
+ "foo.cc"};
+ Mangler(Cmd, "foo.cc");
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ HasSubstr("-isysroot " + testPath("true/sysroot")));
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ Not(HasSubstr(testPath("fake/sysroot"))));
+ }
+
+ {
+ tooling::CompileCommand Cmd;
+ Cmd.CommandLine = {"clang++", "-isysroot" + testPath("true/sysroot"),
+ "foo.cc"};
+ Mangler(Cmd, "foo.cc");
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ HasSubstr("-isysroot" + testPath("true/sysroot")));
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ Not(HasSubstr(testPath("fake/sysroot"))));
+ }
+
+ {
+ tooling::CompileCommand Cmd;
+ Cmd.CommandLine = {"clang++", "--sysroot", testPath("true/sysroot"),
+ "foo.cc"};
+ Mangler(Cmd, "foo.cc");
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ HasSubstr("--sysroot " + testPath("true/sysroot")));
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ Not(HasSubstr(testPath("fake/sysroot"))));
+ }
+
+ {
+ tooling::CompileCommand Cmd;
+ Cmd.CommandLine = {"clang++", "--sysroot=" + testPath("true/sysroot"),
+ "foo.cc"};
+ Mangler(Cmd, "foo.cc");
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ HasSubstr("--sysroot=" + testPath("true/sysroot")));
+ EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+ Not(HasSubstr(testPath("fake/sysroot"))));
+ }
+}
} // namespace
} // namespace clangd
} // namespace clang
|
…cates CommandMangler should guess the sysroot path of the host system and add that through `-isysroot` flag only when there is no `--sysroot` or `-isysroot` flag in the original compile command to avoid duplicate sysroot. Previously, CommandMangler appropriately avoided adding a guessed sysroot flag if the original command had an argument in the form of `--sysroot=<sysroot>`, `--sysroot <sysroot>`, or `-isysroot <sysroot>`. However, when presented as `-isysroot<sysroot>` (without spaces after `-isysroot`), CommandMangler mistakenly appended the guessed sysroot flag, resulting in duplicated sysroot in the final command. This commit fixes it, ensuring the final command has no duplicate sysroot flags. Also adds unit tests for this fix.
1a6a38f
to
5a295dd
Compare
-isysroot
in the original command is respected
Hello @HighCommander4 , Could you take a look at this change? Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, LGTM!
Hello @HighCommander4, Thank you for the review. |
Sure, done. |
…cates (llvm#75694) CommandMangler should guess the sysroot path of the host system and add that through `-isysroot` flag only when there is no `--sysroot` or `-isysroot` flag in the original compile command to avoid duplicate sysroot. Previously, CommandMangler appropriately avoided adding a guessed sysroot flag if the original command had an argument in the form of `--sysroot=<sysroot>`, `--sysroot <sysroot>`, or `-isysroot <sysroot>`. However, when presented as `-isysroot<sysroot>` (without spaces after `-isysroot`), CommandMangler mistakenly appended the guessed sysroot flag, resulting in duplicated sysroot in the final command. This commit fixes it, ensuring the final command has no duplicate sysroot flags. Also adds unit tests for this fix.
CommandMangler should guess the sysroot path of the host system and add that through
-isysroot
flag only when there is no--sysroot
or-isysroot
flag in the original compile command to avoid duplicate sysroot.Previously, CommandMangler appropriately avoided adding a guessed sysroot flag if the original command had an argument in the form of
--sysroot=<sysroot>
,--sysroot <sysroot>
, or-isysroot <sysroot>
.However, when presented as
-isysroot<sysroot>
(without spaces after-isysroot
), CommandMangler mistakenly appended the guessed sysroot flag, resulting in duplicated sysroot in the final command.This commit fixes it, ensuring the final command has no duplicate sysroot flags.
Also adds unit tests for this fix.