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/Support/FileSystem.h"
22#include "llvm/Support/Path.h"
23#include "llvm/Support/Process.h"
24#include "llvm/Support/TargetSelect.h"
26#include "gmock/gmock.h"
27#include "gtest/gtest.h"
34using ::testing::Contains;
35using ::testing::ElementsAre;
36using ::testing::HasSubstr;
45TEST(CommandMangler, Everything) {
46 llvm::InitializeAllTargetInfos();
47 std::string Target = getAnyTargetForTesting();
49 Mangler.ClangPath =
testPath(
"fake/clang");
50 Mangler.ResourceDir =
testPath(
"fake/resources");
51 Mangler.Sysroot =
testPath(
"fake/sysroot");
52 tooling::CompileCommand Cmd;
53 Cmd.CommandLine = {Target +
"-clang++",
"--",
"foo.cc",
"bar.cc"};
54 Mangler(Cmd,
"foo.cc");
55 EXPECT_THAT(Cmd.CommandLine,
56 ElementsAre(
testPath(
"fake/" + Target +
"-clang++"),
57 "--target=" + Target,
"--driver-mode=g++",
58 "-resource-dir=" +
testPath(
"fake/resources"),
59 "-isysroot",
testPath(
"fake/sysroot"),
"--",
63TEST(CommandMangler, FilenameMismatch) {
65 Mangler.ClangPath =
testPath(
"clang");
67 tooling::CompileCommand Cmd;
68 Cmd.CommandLine = {
"clang",
"foo.cc"};
70 Mangler(Cmd,
"foo.h");
72 EXPECT_THAT(Cmd.CommandLine, ElementsAre(
testPath(
"clang"),
"-x",
73 "c++-header",
"--",
"foo.h"));
76TEST(CommandMangler, ResourceDir) {
78 Mangler.ResourceDir =
testPath(
"fake/resources");
79 tooling::CompileCommand Cmd;
80 Cmd.CommandLine = {
"clang++",
"foo.cc"};
81 Mangler(Cmd,
"foo.cc");
82 EXPECT_THAT(Cmd.CommandLine,
83 Contains(
"-resource-dir=" +
testPath(
"fake/resources")));
88 Mangler.Sysroot =
testPath(
"fake/sysroot");
90 tooling::CompileCommand Cmd;
91 Cmd.CommandLine = {
"clang++",
"foo.cc"};
92 Mangler(Cmd,
"foo.cc");
93 EXPECT_THAT(llvm::join(Cmd.CommandLine,
" "),
94 HasSubstr(
"-isysroot " +
testPath(
"fake/sysroot")));
97TEST(CommandMangler, ClangPath) {
99 Mangler.ClangPath =
testPath(
"fake/clang");
101 tooling::CompileCommand Cmd;
102 Cmd.CommandLine = {
"clang++",
"foo.cc"};
103 Mangler(Cmd,
"foo.cc");
104 EXPECT_EQ(
testPath(
"fake/clang++"), Cmd.CommandLine.front());
106 Cmd.CommandLine = {
"unknown-binary",
"foo.cc"};
107 Mangler(Cmd,
"foo.cc");
108 EXPECT_EQ(
testPath(
"fake/unknown-binary"), Cmd.CommandLine.front());
110 Cmd.CommandLine = {
testPath(
"path/clang++"),
"foo.cc"};
111 Mangler(Cmd,
"foo.cc");
112 EXPECT_EQ(
testPath(
"path/clang++"), Cmd.CommandLine.front());
114 Cmd.CommandLine = {
"foo/unknown-binary",
"foo.cc"};
115 Mangler(Cmd,
"foo.cc");
116 EXPECT_EQ(
"foo/unknown-binary", Cmd.CommandLine.front());
124 *result_listener << arg.message();
130TEST(CommandMangler, ClangPathResolve) {
137 llvm::SmallString<256> TempDir;
138 ASSERT_THAT(llvm::sys::fs::createUniqueDirectory(
"ClangPathResolve", TempDir),
141 ASSERT_THAT(llvm::sys::fs::real_path(TempDir.str(), TempDir), ok());
142 auto CleanDir = llvm::make_scope_exit(
143 [&] { llvm::sys::fs::remove_directories(TempDir); });
144 ASSERT_THAT(llvm::sys::fs::create_directory(TempDir +
"/bin"), ok());
145 ASSERT_THAT(llvm::sys::fs::create_directory(TempDir +
"/lib"), ok());
147 ASSERT_THAT(llvm::sys::fs::openFileForWrite(TempDir +
"/lib/bar", FD), ok());
148 ASSERT_THAT(llvm::sys::Process::SafelyCloseFileDescriptor(FD), ok());
149 ::chmod((TempDir +
"/lib/bar").str().c_str(), 0755);
151 llvm::sys::fs::create_link(TempDir +
"/lib/bar", TempDir +
"/bin/foo"),
156 Mangler.ClangPath =
testPath(
"fake/clang");
157 tooling::CompileCommand Cmd;
158 Cmd.CommandLine = {(TempDir +
"/bin/foo").str(),
"foo.cc"};
159 Mangler(Cmd,
"foo.cc");
161 EXPECT_EQ((TempDir +
"/lib/foo").str(), Cmd.CommandLine.front());
164 ASSERT_TRUE(::getenv(
"PATH"));
166 llvm::make_scope_exit([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());
187TEST(CommandMangler, ConfigEdits) {
189 tooling::CompileCommand Cmd;
190 Cmd.CommandLine = {
"clang++",
"foo.cc"};
194 for (
auto &Arg : Argv)
196 C = llvm::toUpper(
C);
199 Argv = tooling::getInsertArgumentAdjuster(
"--hello")(Argv,
"");
201 WithContextValue WithConfig(
Config::Key, std::move(Cfg));
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" $)";
379TEST(CommandMangler, InputsAfterDashDash) {
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"))));
414TEST(CommandMangler, StripsMultipleArch) {
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"; }),
431TEST(CommandMangler, EmptyArgs) {
433 tooling::CompileCommand Cmd;
434 Cmd.CommandLine = {};
436 Mangler(Cmd,
"foo.cc");
439TEST(CommandMangler, PathsAsPositional) {
441 tooling::CompileCommand Cmd;
449 Mangler(Cmd,
"a.cc");
450 EXPECT_THAT(Cmd.CommandLine, Contains(
"foo"));
453TEST(CommandMangler, RespectsOriginalResourceDir) {
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"))));
480TEST(CommandMangler, RespectsOriginalSysroot) {
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"))));
std::vector< const char * > Expected
@ 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()
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
struct clang::clangd::Config::@2 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.