14#include "clang/Testing/CommandLineArgs.h"
15#include "clang/Tooling/ArgumentsAdjusters.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/ScopeExit.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Config/llvm-config.h"
22#include "llvm/Support/FileSystem.h"
23#include "llvm/Support/Path.h"
24#include "llvm/Support/Process.h"
25#include "llvm/Support/TargetSelect.h"
27#include "gmock/gmock.h"
28#include "gtest/gtest.h"
35using ::testing::Contains;
36using ::testing::ElementsAre;
37using ::testing::HasSubstr;
47 llvm::InitializeAllTargetInfos();
48 std::string Target = getAnyTargetForTesting();
50 Mangler.ClangPath =
testPath(
"fake/clang");
51 Mangler.ResourceDir =
testPath(
"fake/resources");
52 Mangler.Sysroot =
testPath(
"fake/sysroot");
53 tooling::CompileCommand Cmd;
54 Cmd.CommandLine = {Target +
"-clang++",
"--",
"foo.cc",
"bar.cc"};
55 Mangler(Cmd,
"foo.cc");
56 EXPECT_THAT(Cmd.CommandLine,
57 ElementsAre(
testPath(
"fake/" + Target +
"-clang++"),
58 "--target=" + Target,
"--driver-mode=g++",
59 "-resource-dir=" +
testPath(
"fake/resources"),
60 "-isysroot",
testPath(
"fake/sysroot"),
"--",
66 Mangler.ClangPath =
testPath(
"clang");
68 tooling::CompileCommand Cmd;
69 Cmd.CommandLine = {
"clang",
"foo.cc"};
71 Mangler(Cmd,
"foo.h");
73 EXPECT_THAT(Cmd.CommandLine, ElementsAre(
testPath(
"clang"),
"-x",
74 "c++-header",
"--",
"foo.h"));
79 Mangler.ResourceDir =
testPath(
"fake/resources");
80 tooling::CompileCommand Cmd;
81 Cmd.CommandLine = {
"clang++",
"foo.cc"};
82 Mangler(Cmd,
"foo.cc");
83 EXPECT_THAT(Cmd.CommandLine,
84 Contains(
"-resource-dir=" +
testPath(
"fake/resources")));
89 Mangler.Sysroot =
testPath(
"fake/sysroot");
91 tooling::CompileCommand Cmd;
92 Cmd.CommandLine = {
"clang++",
"foo.cc"};
93 Mangler(Cmd,
"foo.cc");
94 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
95 HasSubstr(
"-isysroot " +
testPath(
"fake/sysroot")));
100 Mangler.ClangPath =
testPath(
"fake/clang");
102 tooling::CompileCommand Cmd;
103 Cmd.CommandLine = {
"clang++",
"foo.cc"};
104 Mangler(Cmd,
"foo.cc");
105 EXPECT_EQ(
testPath(
"fake/clang++"), Cmd.CommandLine.front());
107 Cmd.CommandLine = {
"unknown-binary",
"foo.cc"};
108 Mangler(Cmd,
"foo.cc");
109 EXPECT_EQ(
testPath(
"fake/unknown-binary"), Cmd.CommandLine.front());
111 Cmd.CommandLine = {
testPath(
"path/clang++"),
"foo.cc"};
112 Mangler(Cmd,
"foo.cc");
113 EXPECT_EQ(
testPath(
"path/clang++"), Cmd.CommandLine.front());
115 Cmd.CommandLine = {
"foo/unknown-binary",
"foo.cc"};
116 Mangler(Cmd,
"foo.cc");
117 EXPECT_EQ(
"foo/unknown-binary", Cmd.CommandLine.front());
125 *result_listener << arg.message();
138 llvm::SmallString<256> TempDir;
139 ASSERT_THAT(llvm::sys::fs::createUniqueDirectory(
"ClangPathResolve", TempDir),
142 ASSERT_THAT(llvm::sys::fs::real_path(TempDir.str(), TempDir), ok());
143 llvm::scope_exit CleanDir(
144 [&] { llvm::sys::fs::remove_directories(TempDir); });
145 ASSERT_THAT(llvm::sys::fs::create_directory(TempDir +
"/bin"), ok());
146 ASSERT_THAT(llvm::sys::fs::create_directory(TempDir +
"/lib"), ok());
148 ASSERT_THAT(llvm::sys::fs::openFileForWrite(TempDir +
"/lib/bar", FD), ok());
149 ASSERT_THAT(llvm::sys::Process::SafelyCloseFileDescriptor(FD), ok());
150 ::chmod((TempDir +
"/lib/bar").str().c_str(), 0755);
152 llvm::sys::fs::create_link(TempDir +
"/lib/bar", TempDir +
"/bin/foo"),
157 Mangler.ClangPath =
testPath(
"fake/clang");
158 tooling::CompileCommand Cmd;
159 Cmd.CommandLine = {(TempDir +
"/bin/foo").str(),
"foo.cc"};
160 Mangler(Cmd,
"foo.cc");
162 EXPECT_EQ((TempDir +
"/lib/foo").str(), Cmd.CommandLine.front());
165 ASSERT_TRUE(::getenv(
"PATH"));
166 llvm::scope_exit RestorePath([OldPath = std::string(::getenv(
"PATH"))] {
167 ::setenv(
"PATH", OldPath.c_str(), 1);
169 ::setenv(
"PATH", (TempDir +
"/bin").str().c_str(), 1);
173 Mangler.ClangPath =
testPath(
"fake/clang");
175 Cmd.CommandLine = {
"foo",
"foo.cc"};
176 Mangler(Cmd,
"foo.cc");
178 EXPECT_EQ((TempDir +
"/lib/foo").str(), Cmd.CommandLine.front());
181 Cmd.CommandLine = {
"foo",
"-no-canonical-prefixes",
"foo.cc"};
182 Mangler(Cmd,
"foo.cc");
183 EXPECT_EQ((TempDir +
"/bin/foo").str(), Cmd.CommandLine.front());
189 tooling::CompileCommand Cmd;
190 Cmd.CommandLine = {
"clang++",
"foo.cc"};
194 for (
auto &Arg : Argv)
196 C = llvm::toUpper(C);
198 Cfg.CompileFlags.Edits.push_back([](std::vector<std::string> &Argv) {
199 Argv = tooling::getInsertArgumentAdjuster(
"--hello")(Argv,
"");
202 Mangler(Cmd,
"foo.cc");
208 EXPECT_THAT(Cmd.CommandLine,
209 ElementsAre(_,
"--driver-mode=g++",
"--hello",
"--",
"FOO.CC"));
212static std::string strip(llvm::StringRef Arg, llvm::StringRef Argv) {
213 llvm::SmallVector<llvm::StringRef> Parts;
214 llvm::SplitString(Argv, Parts);
215 std::vector<std::string> Args = {Parts.begin(), Parts.end()};
222TEST(ArgStripperTest, Spellings) {
224 EXPECT_EQ(strip(
"-pedantic",
"clang -pedantic foo.cc"),
"clang foo.cc");
225 EXPECT_EQ(strip(
"-pedantic",
"clang --pedantic foo.cc"),
"clang foo.cc");
226 EXPECT_EQ(strip(
"--pedantic",
"clang -pedantic foo.cc"),
"clang foo.cc");
227 EXPECT_EQ(strip(
"--pedantic",
"clang --pedantic foo.cc"),
"clang foo.cc");
229 EXPECT_EQ(strip(
"-x",
"clang -x c++ foo.cc"),
"clang foo.cc");
230 EXPECT_EQ(strip(
"-x",
"clang --language=c++ foo.cc"),
"clang foo.cc");
231 EXPECT_EQ(strip(
"--language=",
"clang -x c++ foo.cc"),
"clang foo.cc");
232 EXPECT_EQ(strip(
"--language=",
"clang --language=c++ foo.cc"),
236TEST(ArgStripperTest, UnknownFlag) {
237 EXPECT_EQ(strip(
"-xyzzy",
"clang -xyzzy foo.cc"),
"clang foo.cc");
238 EXPECT_EQ(strip(
"-xyz*",
"clang -xyzzy foo.cc"),
"clang foo.cc");
239 EXPECT_EQ(strip(
"-xyzzy",
"clang -Xclang -xyzzy foo.cc"),
"clang foo.cc");
242TEST(ArgStripperTest, Xclang) {
244 EXPECT_EQ(strip(
"-ast-dump",
"clang -Xclang -ast-dump foo.cc"),
247 EXPECT_EQ(strip(
"-add-plugin",
"clang -Xclang -add-plugin -Xclang z foo.cc"),
251TEST(ArgStripperTest, ClangCL) {
254 EXPECT_EQ(strip(
"-I",
"clang -I /usr/inc /Interesting/file.cc"),
255 "clang /Interesting/file.cc");
257 EXPECT_EQ(strip(
"-I",
"clang-cl -I /usr/inc /Interesting/file.cc"),
260 EXPECT_EQ(strip(
"-I",
"CL.EXE -I /usr/inc /Interesting/file.cc"),
"CL.EXE");
262 EXPECT_EQ(strip(
"-I",
"cc -I /usr/inc /Interesting/file.cc --driver-mode=cl"),
263 "cc --driver-mode=cl");
266TEST(ArgStripperTest, ArgStyles) {
268 EXPECT_EQ(strip(
"-Qn",
"clang -Qn foo.cc"),
"clang foo.cc");
269 EXPECT_EQ(strip(
"-Qn",
"clang -QnZ foo.cc"),
"clang -QnZ foo.cc");
271 EXPECT_EQ(strip(
"-std=",
"clang -std= foo.cc"),
"clang foo.cc");
272 EXPECT_EQ(strip(
"-std=",
"clang -std=c++11 foo.cc"),
"clang foo.cc");
274 EXPECT_EQ(strip(
"-mllvm",
"clang -mllvm X foo.cc"),
"clang foo.cc");
275 EXPECT_EQ(strip(
"-mllvm",
"clang -mllvmX foo.cc"),
"clang -mllvmX foo.cc");
277 EXPECT_EQ(strip(
"/link",
"clang-cl /link b c d foo.cc"),
"clang-cl");
278 EXPECT_EQ(strip(
"/link",
"clang-cl /linka b c d foo.cc"),
"clang-cl");
280 EXPECT_EQ(strip(
"-Wl,",
"clang -Wl,x,y foo.cc"),
"clang foo.cc");
281 EXPECT_EQ(strip(
"-Wl,",
"clang -Wl, foo.cc"),
"clang foo.cc");
283 EXPECT_EQ(strip(
"-segaddr",
"clang -segaddr a b foo.cc"),
"clang foo.cc");
284 EXPECT_EQ(strip(
"-segaddr",
"clang -segaddra b foo.cc"),
285 "clang -segaddra b foo.cc");
287 EXPECT_EQ(strip(
"-G",
"clang -GX foo.cc"),
"clang foo.cc");
288 EXPECT_EQ(strip(
"-G",
"clang -G X foo.cc"),
"clang foo.cc");
290 EXPECT_EQ(strip(
"-plugin-arg-",
"clang -cc1 -plugin-arg-X Y foo.cc"),
291 "clang -cc1 foo.cc");
292 EXPECT_EQ(strip(
"-plugin-arg-",
"clang -cc1 -plugin-arg- Y foo.cc"),
293 "clang -cc1 foo.cc");
296TEST(ArgStripperTest, EndOfList) {
299 EXPECT_EQ(strip(
"-I",
"clang -Xclang"),
"clang -Xclang");
300 EXPECT_EQ(strip(
"-I",
"clang -Xclang -I"),
"clang");
301 EXPECT_EQ(strip(
"-I",
"clang -I -Xclang"),
"clang");
302 EXPECT_EQ(strip(
"-I",
"clang -I"),
"clang");
305TEST(ArgStripperTest, Multiple) {
309 std::vector<std::string> Args = {
"clang",
"-o",
"foo.o",
"foo.cc",
"-c"};
311 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
319 std::vector<std::string> Args = {
"clang",
"-Wfoo",
"-Wno-bar",
"-Werror",
322 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
328 std::vector<std::string> Args = {
"clang",
"-Wunused",
"-Wno-unused",
331 EXPECT_THAT(Args, ElementsAre(
"clang",
"-Wno-unused",
"foo.cc"));
335TEST(ArgStripperTest, Define) {
340 std::vector<std::string> Args = {
"clang",
"-Dfoo",
"-Dbar=baz",
"foo.cc"};
342 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
348 std::vector<std::string> Args = {
"clang",
"-Dfoo",
"-Dbar=baz",
"foo.cc"};
350 EXPECT_THAT(Args, ElementsAre(
"clang",
"-Dfoo",
"-Dbar=baz",
"foo.cc"));
353 EXPECT_THAT(Args, ElementsAre(
"clang",
"-Dbar=baz",
"foo.cc"));
356 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
360TEST(ArgStripperTest, OrderDependent) {
365 S.strip(
"-include-pch");
366 std::vector<std::string> Args = {
"clang",
"-include-pch",
"foo.pch",
369 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
373 std::vector<llvm::StringRef> Args = {
"one",
"two",
"thr ee",
374 "f\"o\"ur",
"fi\\ve",
"$"};
375 const char *Expected = R
"(one two "thr ee" "f\"o\"ur" "fi\\ve" $)";
382 tooling::CompileCommand Cmd;
383 Cmd.CommandLine = {
"clang",
"/Users/foo.cc"};
384 Mangler(Cmd,
"/Users/foo.cc");
385 EXPECT_THAT(llvm::ArrayRef(Cmd.CommandLine).take_back(2),
386 ElementsAre(
"--",
"/Users/foo.cc"));
387 EXPECT_THAT(llvm::ArrayRef(Cmd.CommandLine).drop_back(2),
388 Not(Contains(
"/Users/foo.cc")));
393 tooling::CompileCommand Cmd;
394 Cmd.CommandLine = {
"clang",
"--driver-mode=cl",
"bar.cc",
"/Users/foo.cc"};
395 Mangler(Cmd,
"bar.cc");
396 EXPECT_THAT(llvm::ArrayRef(Cmd.CommandLine).take_back(2),
397 ElementsAre(
"--",
"bar.cc"));
398 EXPECT_THAT(llvm::ArrayRef(Cmd.CommandLine).drop_back(2),
399 Not(Contains(
"bar.cc")));
403 tooling::CompileCommand Cmd;
404 Cmd.CommandLine = {
"clang",
"foo.cc",
"bar.cc"};
405 Mangler(Cmd,
"baz.cc");
406 EXPECT_THAT(llvm::ArrayRef(Cmd.CommandLine).take_back(2),
407 ElementsAre(
"--",
"baz.cc"));
409 llvm::ArrayRef(Cmd.CommandLine).drop_back(2),
410 testing::AllOf(Not(Contains(
"foo.cc")), Not(Contains(
"bar.cc"))));
416 tooling::CompileCommand Cmd;
417 Cmd.CommandLine = {
"clang",
"-arch",
"foo",
"-arch",
"bar",
"/Users/foo.cc"};
418 Mangler(Cmd,
"/Users/foo.cc");
419 EXPECT_EQ(llvm::count_if(Cmd.CommandLine,
420 [](llvm::StringRef Arg) { return Arg ==
"-arch"; }),
424 Cmd.CommandLine = {
"clang",
"-arch",
"foo",
"/Users/foo.cc"};
425 Mangler(Cmd,
"/Users/foo.cc");
426 EXPECT_EQ(llvm::count_if(Cmd.CommandLine,
427 [](llvm::StringRef Arg) { return Arg ==
"-arch"; }),
433 tooling::CompileCommand Cmd;
434 Cmd.CommandLine = {};
436 Mangler(Cmd,
"foo.cc");
441 tooling::CompileCommand Cmd;
449 Mangler(Cmd,
"a.cc");
450 EXPECT_THAT(Cmd.CommandLine, Contains(
"foo"));
455 Mangler.ResourceDir =
testPath(
"fake/resources");
458 tooling::CompileCommand Cmd;
459 Cmd.CommandLine = {
"clang++",
"-resource-dir",
testPath(
"true/resources"),
461 Mangler(Cmd,
"foo.cc");
462 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
463 HasSubstr(
"-resource-dir " +
testPath(
"true/resources")));
464 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
465 Not(HasSubstr(
testPath(
"fake/resources"))));
469 tooling::CompileCommand Cmd;
470 Cmd.CommandLine = {
"clang++",
"-resource-dir=" +
testPath(
"true/resources"),
472 Mangler(Cmd,
"foo.cc");
473 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
474 HasSubstr(
"-resource-dir=" +
testPath(
"true/resources")));
475 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
476 Not(HasSubstr(
testPath(
"fake/resources"))));
482 Mangler.Sysroot =
testPath(
"fake/sysroot");
485 tooling::CompileCommand Cmd;
486 Cmd.CommandLine = {
"clang++",
"-isysroot",
testPath(
"true/sysroot"),
488 Mangler(Cmd,
"foo.cc");
489 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
490 HasSubstr(
"-isysroot " +
testPath(
"true/sysroot")));
491 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
492 Not(HasSubstr(
testPath(
"fake/sysroot"))));
496 tooling::CompileCommand Cmd;
497 Cmd.CommandLine = {
"clang++",
"-isysroot" +
testPath(
"true/sysroot"),
499 Mangler(Cmd,
"foo.cc");
500 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
501 HasSubstr(
"-isysroot" +
testPath(
"true/sysroot")));
502 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
503 Not(HasSubstr(
testPath(
"fake/sysroot"))));
507 tooling::CompileCommand Cmd;
508 Cmd.CommandLine = {
"clang++",
"--sysroot",
testPath(
"true/sysroot"),
510 Mangler(Cmd,
"foo.cc");
511 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
512 HasSubstr(
"--sysroot " +
testPath(
"true/sysroot")));
513 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
514 Not(HasSubstr(
testPath(
"fake/sysroot"))));
518 tooling::CompileCommand Cmd;
519 Cmd.CommandLine = {
"clang++",
"--sysroot=" +
testPath(
"true/sysroot"),
521 Mangler(Cmd,
"foo.cc");
522 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
523 HasSubstr(
"--sysroot=" +
testPath(
"true/sysroot")));
524 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
525 Not(HasSubstr(
testPath(
"fake/sysroot"))));
531 tooling::CompileCommand Cmd;
532 Cmd.CommandLine = {
"clang-cl",
"/std:c++latest",
"--",
"/Users/foo.cc"};
533 Mangler(Cmd,
"/Users/foo.cc");
535 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "), HasSubstr(
"/std:c++latest"));
540 tooling::CompileCommand Cmd;
541 Cmd.CommandLine = {
"clang-cl",
"/std:c++latest",
"--",
"/Users/foo.cc"};
542 Mangler(Cmd,
"/Users/foo.hpp");
544 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "), HasSubstr(
"/std:c++latest"));
void strip(llvm::StringRef Arg)
WithContextValue extends Context::current() with a single value.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
@ Warning
A warning message.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
TEST(BackgroundQueueTest, Priority)
std::string printArgv(llvm::ArrayRef< llvm::StringRef > Args)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static CommandMangler forTests()
Settings that express user/project preferences and control clangd behavior.
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
struct clang::clangd::Config::@347104204155140144054042115114221214347344026246 CompileFlags
Controls how the compile command for the current file is determined.
std::vector< llvm::unique_function< void(std::vector< std::string > &) const > > Edits
Edits to apply to the compile command, in sequence.