14 #include "llvm/ADT/ScopeExit.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/Support/Process.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
28 using ::testing::Contains;
29 using ::testing::ElementsAre;
30 using ::testing::HasSubstr;
39 TEST(CommandMangler, Everything) {
41 Mangler.ClangPath =
testPath(
"fake/clang");
42 Mangler.ResourceDir =
testPath(
"fake/resources");
43 Mangler.Sysroot =
testPath(
"fake/sysroot");
44 std::vector<std::string> Cmd = {
"clang++",
"-Xclang",
"-load",
"-Xclang",
45 "plugin",
"-MF",
"dep",
"foo.cc"};
47 EXPECT_THAT(Cmd, ElementsAre(
testPath(
"fake/clang++"),
"foo.cc",
49 "-resource-dir=" +
testPath(
"fake/resources"),
50 "-isysroot",
testPath(
"fake/sysroot")));
53 TEST(CommandMangler, ResourceDir) {
55 Mangler.ResourceDir =
testPath(
"fake/resources");
56 std::vector<std::string> Cmd = {
"clang++",
"foo.cc"};
58 EXPECT_THAT(Cmd, Contains(
"-resource-dir=" +
testPath(
"fake/resources")));
61 TEST(CommandMangler, Sysroot) {
63 Mangler.Sysroot =
testPath(
"fake/sysroot");
65 std::vector<std::string> Cmd = {
"clang++",
"foo.cc"};
68 HasSubstr(
"-isysroot " +
testPath(
"fake/sysroot")));
71 TEST(CommandMangler, StripPlugins) {
73 std::vector<std::string> Cmd = {
"clang++",
"-Xclang",
"-load",
74 "-Xclang",
"plugin",
"foo.cc"};
76 for (
const char* Stripped : {
"-Xclang",
"-load",
"plugin"})
77 EXPECT_THAT(Cmd, Not(Contains(Stripped)));
80 TEST(CommandMangler, StripOutput) {
82 std::vector<std::string> Cmd = {
"clang++",
"-MF",
"dependency",
"-c",
85 for (
const char* Stripped : {
"-MF",
"dependency"})
86 EXPECT_THAT(Cmd, Not(Contains(Stripped)));
89 TEST(CommandMangler, StripShowIncludes) {
91 std::vector<std::string> Cmd = {
"clang-cl",
"/showIncludes",
"foo.cc"};
93 EXPECT_THAT(Cmd, Not(Contains(
"/showIncludes")));
96 TEST(CommandMangler, StripShowIncludesUser) {
98 std::vector<std::string> Cmd = {
"clang-cl",
"/showIncludes:user",
"foo.cc"};
100 EXPECT_THAT(Cmd, Not(Contains(
"/showIncludes:user")));
103 TEST(CommandMangler, ClangPath) {
105 Mangler.ClangPath =
testPath(
"fake/clang");
107 std::vector<std::string> Cmd = {
"clang++",
"foo.cc"};
109 EXPECT_EQ(
testPath(
"fake/clang++"), Cmd.front());
111 Cmd = {
"unknown-binary",
"foo.cc"};
113 EXPECT_EQ(
testPath(
"fake/unknown-binary"), Cmd.front());
115 Cmd = {
testPath(
"path/clang++"),
"foo.cc"};
117 EXPECT_EQ(
testPath(
"path/clang++"), Cmd.front());
119 Cmd = {
"foo/unknown-binary",
"foo.cc"};
121 EXPECT_EQ(
"foo/unknown-binary", Cmd.front());
129 *result_listener << arg.message();
135 TEST(CommandMangler, ClangPathResolve) {
142 llvm::SmallString<256> TempDir;
143 ASSERT_THAT(llvm::sys::fs::createUniqueDirectory(
"ClangPathResolve", TempDir),
146 ASSERT_THAT(llvm::sys::fs::real_path(TempDir.str(), TempDir), Ok());
147 auto CleanDir = llvm::make_scope_exit(
148 [&] { llvm::sys::fs::remove_directories(TempDir); });
149 ASSERT_THAT(llvm::sys::fs::create_directory(TempDir +
"/bin"), Ok());
150 ASSERT_THAT(llvm::sys::fs::create_directory(TempDir +
"/lib"), Ok());
152 ASSERT_THAT(llvm::sys::fs::openFileForWrite(TempDir +
"/lib/bar", FD), Ok());
153 ASSERT_THAT(llvm::sys::Process::SafelyCloseFileDescriptor(FD), Ok());
154 ::chmod((TempDir +
"/lib/bar").str().c_str(), 0755);
156 llvm::sys::fs::create_link(TempDir +
"/lib/bar", TempDir +
"/bin/foo"),
161 Mangler.ClangPath =
testPath(
"fake/clang");
162 std::vector<std::string> Cmd = {(TempDir +
"/bin/foo").str(),
"foo.cc"};
165 EXPECT_EQ((TempDir +
"/lib/foo").str(), Cmd.front());
168 ASSERT_TRUE(::getenv(
"PATH"));
170 llvm::make_scope_exit([OldPath = std::string(::getenv(
"PATH"))] {
171 ::setenv(
"PATH", OldPath.c_str(), 1);
173 ::setenv(
"PATH", (TempDir +
"/bin").str().c_str(), 1);
177 Mangler.ClangPath =
testPath(
"fake/clang");
179 Cmd = {
"foo",
"foo.cc"};
182 EXPECT_EQ((TempDir +
"/lib/foo").str(), Cmd.front());
185 Cmd = {
"foo",
"-no-canonical-prefixes",
"foo.cc"};
187 EXPECT_EQ((TempDir +
"/bin/foo").str(), Cmd.front());
191 TEST(CommandMangler, ConfigEdits) {
193 std::vector<std::string> Cmd = {
"clang++",
"foo.cc"};
196 Cfg.CompileFlags.Edits.push_back([](std::vector<std::string> &Argv) {
197 for (
auto &Arg : Argv)
199 C = llvm::toUpper(C);
201 Cfg.CompileFlags.Edits.push_back(
202 [](std::vector<std::string> &Argv) { Argv.push_back(
"--hello"); });
203 WithContextValue WithConfig(
Config::Key, std::move(Cfg));
207 EXPECT_THAT(Cmd, ElementsAre(_,
"FOO.CC",
"--hello",
"-fsyntax-only"));
210 static std::string strip(llvm::StringRef Arg, llvm::StringRef Argv) {
211 llvm::SmallVector<llvm::StringRef, 8> Parts;
212 llvm::SplitString(Argv, Parts);
213 std::vector<std::string> Args = {Parts.begin(), Parts.end()};
220 TEST(ArgStripperTest, Spellings) {
222 EXPECT_EQ(strip(
"-pedantic",
"clang -pedantic foo.cc"),
"clang foo.cc");
223 EXPECT_EQ(strip(
"-pedantic",
"clang --pedantic foo.cc"),
"clang foo.cc");
224 EXPECT_EQ(strip(
"--pedantic",
"clang -pedantic foo.cc"),
"clang foo.cc");
225 EXPECT_EQ(strip(
"--pedantic",
"clang --pedantic foo.cc"),
"clang foo.cc");
227 EXPECT_EQ(strip(
"-x",
"clang -x c++ foo.cc"),
"clang foo.cc");
228 EXPECT_EQ(strip(
"-x",
"clang --language=c++ foo.cc"),
"clang foo.cc");
229 EXPECT_EQ(strip(
"--language=",
"clang -x c++ foo.cc"),
"clang foo.cc");
230 EXPECT_EQ(strip(
"--language=",
"clang --language=c++ foo.cc"),
234 TEST(ArgStripperTest, UnknownFlag) {
235 EXPECT_EQ(strip(
"-xyzzy",
"clang -xyzzy foo.cc"),
"clang foo.cc");
236 EXPECT_EQ(strip(
"-xyz*",
"clang -xyzzy foo.cc"),
"clang foo.cc");
237 EXPECT_EQ(strip(
"-xyzzy",
"clang -Xclang -xyzzy foo.cc"),
"clang foo.cc");
240 TEST(ArgStripperTest, Xclang) {
242 EXPECT_EQ(strip(
"-ast-dump",
"clang -Xclang -ast-dump foo.cc"),
245 EXPECT_EQ(strip(
"-add-plugin",
"clang -Xclang -add-plugin -Xclang z foo.cc"),
249 TEST(ArgStripperTest, ClangCL) {
252 EXPECT_EQ(strip(
"-I",
"clang -I /usr/inc /Interesting/file.cc"),
253 "clang /Interesting/file.cc");
255 EXPECT_EQ(strip(
"-I",
"clang-cl -I /usr/inc /Interesting/file.cc"),
258 EXPECT_EQ(strip(
"-I",
"CL.EXE -I /usr/inc /Interesting/file.cc"),
"CL.EXE");
260 EXPECT_EQ(strip(
"-I",
"cc -I /usr/inc /Interesting/file.cc --driver-mode=cl"),
261 "cc --driver-mode=cl");
264 TEST(ArgStripperTest, ArgStyles) {
266 EXPECT_EQ(strip(
"-Qn",
"clang -Qn foo.cc"),
"clang foo.cc");
267 EXPECT_EQ(strip(
"-Qn",
"clang -QnZ foo.cc"),
"clang -QnZ foo.cc");
269 EXPECT_EQ(strip(
"-std=",
"clang -std= foo.cc"),
"clang foo.cc");
270 EXPECT_EQ(strip(
"-std=",
"clang -std=c++11 foo.cc"),
"clang foo.cc");
272 EXPECT_EQ(strip(
"-mllvm",
"clang -mllvm X foo.cc"),
"clang foo.cc");
273 EXPECT_EQ(strip(
"-mllvm",
"clang -mllvmX foo.cc"),
"clang -mllvmX foo.cc");
275 EXPECT_EQ(strip(
"/link",
"clang-cl /link b c d foo.cc"),
"clang-cl");
276 EXPECT_EQ(strip(
"/link",
"clang-cl /linka b c d foo.cc"),
"clang-cl");
278 EXPECT_EQ(strip(
"-Wl,",
"clang -Wl,x,y foo.cc"),
"clang foo.cc");
279 EXPECT_EQ(strip(
"-Wl,",
"clang -Wl, foo.cc"),
"clang foo.cc");
281 EXPECT_EQ(strip(
"-segaddr",
"clang -segaddr a b foo.cc"),
"clang foo.cc");
282 EXPECT_EQ(strip(
"-segaddr",
"clang -segaddra b foo.cc"),
283 "clang -segaddra b foo.cc");
285 EXPECT_EQ(strip(
"-G",
"clang -GX foo.cc"),
"clang foo.cc");
286 EXPECT_EQ(strip(
"-G",
"clang -G X foo.cc"),
"clang foo.cc");
288 EXPECT_EQ(strip(
"-plugin-arg-",
"clang -cc1 -plugin-arg-X Y foo.cc"),
289 "clang -cc1 foo.cc");
290 EXPECT_EQ(strip(
"-plugin-arg-",
"clang -cc1 -plugin-arg- Y foo.cc"),
291 "clang -cc1 foo.cc");
294 TEST(ArgStripperTest, EndOfList) {
297 EXPECT_EQ(strip(
"-I",
"clang -Xclang"),
"clang -Xclang");
298 EXPECT_EQ(strip(
"-I",
"clang -Xclang -I"),
"clang");
299 EXPECT_EQ(strip(
"-I",
"clang -I -Xclang"),
"clang");
300 EXPECT_EQ(strip(
"-I",
"clang -I"),
"clang");
303 TEST(ArgStripperTest, Multiple) {
307 std::vector<std::string> Args = {
"clang",
"-o",
"foo.o",
"foo.cc",
"-c"};
309 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
312 TEST(ArgStripperTest, Warning) {
317 std::vector<std::string> Args = {
"clang",
"-Wfoo",
"-Wno-bar",
"-Werror",
320 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
326 std::vector<std::string> Args = {
"clang",
"-Wunused",
"-Wno-unused",
329 EXPECT_THAT(Args, ElementsAre(
"clang",
"-Wno-unused",
"foo.cc"));
333 TEST(ArgStripperTest, Define) {
338 std::vector<std::string> Args = {
"clang",
"-Dfoo",
"-Dbar=baz",
"foo.cc"};
340 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
346 std::vector<std::string> Args = {
"clang",
"-Dfoo",
"-Dbar=baz",
"foo.cc"};
348 EXPECT_THAT(Args, ElementsAre(
"clang",
"-Dfoo",
"-Dbar=baz",
"foo.cc"));
351 EXPECT_THAT(Args, ElementsAre(
"clang",
"-Dbar=baz",
"foo.cc"));
354 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));
358 TEST(ArgStripperTest, OrderDependent) {
363 S.strip(
"-include-pch");
364 std::vector<std::string> Args = {
"clang",
"-include-pch",
"foo.pch",
367 EXPECT_THAT(Args, ElementsAre(
"clang",
"foo.cc"));