Summary: While here, add documentation to CompileFlags and CompileFlags.Add.
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83705
// The table-building strategy may not make sense outside clangd.
class ArgStripper {
public:
+ ArgStripper() = default;
+ ArgStripper(ArgStripper &&) = default;
+ ArgStripper(const ArgStripper &) = delete;
+ ArgStripper &operator=(ArgStripper &&) = default;
+ ArgStripper &operator=(const ArgStripper &) = delete;
+
// Adds the arg to the set which should be removed.
//
// Recognized clang flags are stripped semantically. When "-I" is stripped:
//
//===----------------------------------------------------------------------===//
+#include "CompileCommands.h"
#include "Config.h"
#include "ConfigFragment.h"
#include "support/Logger.h"
}
void compile(Fragment::CompileFlagsBlock &&F) {
+ if (!F.Remove.empty()) {
+ auto Remove = std::make_shared<ArgStripper>();
+ for (auto &A : F.Remove)
+ Remove->strip(*A);
+ Out.Apply.push_back([Remove(std::shared_ptr<const ArgStripper>(
+ std::move(Remove)))](Config &C) {
+ C.CompileFlags.Edits.push_back(
+ [Remove](std::vector<std::string> &Args) {
+ Remove->process(Args);
+ });
+ });
+ }
+
if (!F.Add.empty()) {
std::vector<std::string> Add;
for (auto &A : F.Add)
};
IfBlock If;
+ /// Conditions in the CompileFlags block affect how a file is parsed.
+ ///
+ /// clangd emulates how clang would interpret a file.
+ /// By default, it behaves roughly like `clang $FILENAME`, but real projects
+ /// usually require setting the include path (with the `-I` flag), defining
+ /// preprocessor symbols, configuring warnings etc.
+ /// Often, a compilation database specifies these compile commands. clangd
+ /// searches for compile_commands.json in parents of the source file.
+ ///
+ /// This section modifies how the compile command is constructed.
struct CompileFlagsBlock {
+ /// List of flags to append to the compile command.
std::vector<Located<std::string>> Add;
- } CompileFlags;
+ /// List of flags to remove from the compile command.
+ ///
+ /// - If the value is a recognized clang flag (like "-I") then it will be
+ /// removed along with any arguments. Synonyms like --include-dir= will
+ /// also be removed.
+ /// - Otherwise, if the value ends in * (like "-DFOO=*") then any argument
+ /// with the prefix will be removed.
+ /// - Otherwise any argument exactly matching the value is removed.
+ ///
+ /// In all cases, -Xclang is also removed where needed.
+ ///
+ /// Example:
+ /// Command: clang++ --include-directory=/usr/include -DFOO=42 foo.cc
+ /// Remove: [-I, -DFOO=*]
+ /// Result: clang++ foo.cc
+ ///
+ /// Flags added by the same CompileFlags entry will not be removed.
+ std::vector<Located<std::string>> Remove;
+ };
+ CompileFlagsBlock CompileFlags;
};
} // namespace config
if (auto Values = scalarValues(N))
F.Add = std::move(*Values);
});
+ Dict.handle("Remove", [&](Node &N) {
+ if (auto Values = scalarValues(N))
+ F.Remove = std::move(*Values);
+ });
Dict.parse(N);
}
TEST_F(ConfigCompileTests, CompileCommands) {
Frag.CompileFlags.Add.emplace_back("-foo");
- std::vector<std::string> Argv = {"clang", "a.cc"};
+ Frag.CompileFlags.Remove.emplace_back("--include-directory=");
+ std::vector<std::string> Argv = {"clang", "-I", "bar/", "a.cc"};
EXPECT_TRUE(compileAndApply());
- EXPECT_THAT(Conf.CompileFlags.Edits, SizeIs(1));
- Conf.CompileFlags.Edits.front()(Argv);
+ EXPECT_THAT(Conf.CompileFlags.Edits, SizeIs(2));
+ for (auto &Edit : Conf.CompileFlags.Edits)
+ Edit(Argv);
EXPECT_THAT(Argv, ElementsAre("clang", "a.cc", "-foo"));
}