Revert "Revert "[clangd] Canonicalize compile flags before applying edits""

Set driver mode before parsing arglist.

Depends on D106789.

Differential Revision: https://reviews.llvm.org/D106794
This commit is contained in:
Kadir Cetinkaya 2021-07-26 11:20:47 +02:00
parent ce90b60bd0
commit ab714ba056
No known key found for this signature in database
GPG key ID: E39E36B8D2057ED6
4 changed files with 74 additions and 10 deletions

View file

@ -9,11 +9,17 @@
#include "CompileCommands.h"
#include "Config.h"
#include "support/Logger.h"
#include "support/Trace.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
@ -188,11 +194,43 @@ CommandMangler CommandMangler::detect() {
return Result;
}
CommandMangler CommandMangler::forTests() {
return CommandMangler();
}
CommandMangler CommandMangler::forTests() { return CommandMangler(); }
void CommandMangler::adjust(std::vector<std::string> &Cmd) const {
trace::Span S("AdjustCompileFlags");
auto &OptTable = clang::driver::getDriverOptTable();
// OriginalArgs needs to outlive ArgList.
llvm::SmallVector<const char *, 16> OriginalArgs;
OriginalArgs.reserve(Cmd.size());
for (const auto &S : Cmd)
OriginalArgs.push_back(S.c_str());
bool IsCLMode =
!OriginalArgs.empty() &&
driver::IsClangCL(driver::getDriverMode(
OriginalArgs[0], llvm::makeArrayRef(OriginalArgs).slice(1)));
// ParseArgs propagates missig arg/opt counts on error, but preserves
// everything it could parse in ArgList. So we just ignore those counts.
unsigned IgnoredCount;
auto ArgList = OptTable.ParseArgs(
OriginalArgs, IgnoredCount, IgnoredCount,
/*FlagsToInclude=*/
IsCLMode ? (driver::options::CLOption | driver::options::CoreOption)
: /*everything*/ 0,
/*FlagsToExclude=*/driver::options::NoDriverOption |
(IsCLMode ? 0 : driver::options::CLOption));
// Move the inputs to the end, separated via `--` from flags. This ensures
// modifications done in the following steps apply in more cases (like setting
// -x, which only affects inputs that come after it).
if (!ArgList.hasArgNoClaim(driver::options::OPT__DASH_DASH)) {
// In theory there might be more than one input, but clangd can't deal with
// them anyway.
if (auto *Input = ArgList.getLastArg(driver::options::OPT_INPUT)) {
Cmd.insert(Cmd.end(), {"--", Input->getAsString(ArgList)});
Cmd.erase(Cmd.begin() + Input->getIndex());
}
}
for (auto &Edit : Config::current().CompileFlags.Edits)
Edit(Cmd);

View file

@ -48,7 +48,7 @@
#
# ERR: ASTWorker building file {{.*}}foo.c version 0 with command
# ERR: [{{.*}}clangd-test2]
# ERR: clang -c foo.c -Wall -Werror
# ERR: clang -c -Wall -Werror {{.*}} -- foo.c
---
{"jsonrpc":"2.0","id":5,"method":"shutdown"}
---

View file

@ -133,8 +133,9 @@ TEST_F(BackgroundIndexTest, Config) {
Opts.ContextProvider = [](PathRef P) {
Config C;
if (P.endswith("foo.cpp"))
C.CompileFlags.Edits.push_back(
[](std::vector<std::string> &Argv) { Argv.push_back("-Done=two"); });
C.CompileFlags.Edits.push_back([](std::vector<std::string> &Argv) {
Argv = tooling::getInsertArgumentAdjuster("-Done=two")(Argv, "");
});
if (P.endswith("baz.cpp"))
C.Index.Background = Config::BackgroundPolicy::Skip;
return Context::current().derive(Config::Key, std::move(C));

View file

@ -11,6 +11,8 @@
#include "TestFS.h"
#include "support/Context.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FileSystem.h"
@ -165,13 +167,15 @@ TEST(CommandMangler, ConfigEdits) {
for (char &C : Arg)
C = llvm::toUpper(C);
});
Cfg.CompileFlags.Edits.push_back(
[](std::vector<std::string> &Argv) { Argv.push_back("--hello"); });
Cfg.CompileFlags.Edits.push_back([](std::vector<std::string> &Argv) {
Argv = tooling::getInsertArgumentAdjuster("--hello")(Argv, "");
});
WithContextValue WithConfig(Config::Key, std::move(Cfg));
Mangler.adjust(Cmd);
}
// Edits are applied in given order and before other mangling.
EXPECT_THAT(Cmd, ElementsAre(_, "FOO.CC", "--hello"));
// Edits are applied in given order and before other mangling and they always
// go before filename.
EXPECT_THAT(Cmd, ElementsAre(_, "--hello", "--", "FOO.CC"));
}
static std::string strip(llvm::StringRef Arg, llvm::StringRef Argv) {
@ -342,6 +346,27 @@ TEST(PrintArgvTest, All) {
EXPECT_EQ(Expected, printArgv(Args));
}
TEST(CommandMangler, InputsAfterDashDash) {
const auto Mangler = CommandMangler::forTests();
{
std::vector<std::string> Args = {"clang", "/Users/foo.cc"};
Mangler.adjust(Args);
EXPECT_THAT(llvm::makeArrayRef(Args).take_back(2),
ElementsAre("--", "/Users/foo.cc"));
EXPECT_THAT(llvm::makeArrayRef(Args).drop_back(2),
Not(Contains("/Users/foo.cc")));
}
// In CL mode /U triggers an undef operation, hence `/Users/foo.cc` shouldn't
// be interpreted as a file.
{
std::vector<std::string> Args = {"clang", "--driver-mode=cl", "bar.cc",
"/Users/foo.cc"};
Mangler.adjust(Args);
EXPECT_THAT(llvm::makeArrayRef(Args).take_back(2),
ElementsAre("--", "bar.cc"));
EXPECT_THAT(llvm::makeArrayRef(Args).drop_back(2), Not(Contains("bar.cc")));
}
}
} // namespace
} // namespace clangd
} // namespace clang