xref: /llvm-project/clang/unittests/Frontend/CompilerInvocationTest.cpp (revision 8bf19ec444593b3076a446a8eeb5042bbf79dc65)
1 //===- unittests/Frontend/CompilerInvocationTest.cpp - CI tests //---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Frontend/CompilerInvocation.h"
10 #include "clang/Basic/TargetOptions.h"
11 #include "clang/Frontend/CompilerInstance.h"
12 #include "clang/Frontend/TextDiagnosticBuffer.h"
13 #include "clang/Lex/PreprocessorOptions.h"
14 #include "clang/Serialization/ModuleFileExtension.h"
15 #include "llvm/Support/VirtualFileSystem.h"
16 #include "llvm/TargetParser/Host.h"
17 
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 
21 using namespace llvm;
22 using namespace clang;
23 
24 using ::testing::Contains;
25 using ::testing::HasSubstr;
26 using ::testing::StrEq;
27 using ::testing::StartsWith;
28 
29 namespace {
30 class CommandLineTest : public ::testing::Test {
31 public:
32   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
33   SmallVector<const char *, 32> GeneratedArgs;
34   BumpPtrAllocator Alloc;
35   StringSaver StringPool;
36   CompilerInvocation Invocation;
37 
38   const char *operator()(const Twine &Arg) {
39     return StringPool.save(Arg).data();
40   }
41 
42   CommandLineTest()
43       : Diags(CompilerInstance::createDiagnostics(
44             *llvm::vfs::getRealFileSystem(), new DiagnosticOptions(),
45             new TextDiagnosticBuffer())),
46         StringPool(Alloc) {}
47 };
48 
49 template <typename M>
50 std::string describeContainsN(M InnerMatcher, unsigned N, bool Negation) {
51   StringRef Contains = Negation ? "doesn't contain" : "contains";
52   StringRef Instance = N == 1 ? " instance " : " instances ";
53   StringRef Element = "of element that ";
54 
55   std::ostringstream Inner;
56   InnerMatcher.impl().DescribeTo(&Inner);
57 
58   return (Contains + " exactly " + Twine(N) + Instance + Element + Inner.str())
59       .str();
60 }
61 
62 MATCHER_P2(ContainsN, InnerMatcher, N,
63            describeContainsN(InnerMatcher, N, negation)) {
64   auto InnerMatches = [this](const auto &Element) {
65     ::testing::internal::DummyMatchResultListener InnerListener;
66     return InnerMatcher.impl().MatchAndExplain(Element, &InnerListener);
67   };
68 
69   return count_if(arg, InnerMatches) == N;
70 }
71 
72 TEST(ContainsN, Empty) {
73   const char *Array[] = {""};
74 
75   ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
76   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
77   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
78 }
79 
80 TEST(ContainsN, Zero) {
81   const char *Array[] = {"y"};
82 
83   ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
84   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
85   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
86 }
87 
88 TEST(ContainsN, One) {
89   const char *Array[] = {"a", "b", "x", "z"};
90 
91   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
92   ASSERT_THAT(Array, ContainsN(StrEq("x"), 1));
93   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
94 }
95 
96 TEST(ContainsN, Two) {
97   const char *Array[] = {"x", "a", "b", "x"};
98 
99   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
100   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
101   ASSERT_THAT(Array, ContainsN(StrEq("x"), 2));
102 }
103 
104 // Copy constructor/assignment perform deep copy of reference-counted pointers.
105 
106 TEST(CompilerInvocationTest, DeepCopyConstructor) {
107   CompilerInvocation A;
108   A.getAnalyzerOpts().Config["Key"] = "Old";
109 
110   CompilerInvocation B(A);
111   B.getAnalyzerOpts().Config["Key"] = "New";
112 
113   ASSERT_EQ(A.getAnalyzerOpts().Config["Key"], "Old");
114 }
115 
116 TEST(CompilerInvocationTest, DeepCopyAssignment) {
117   CompilerInvocation A;
118   A.getAnalyzerOpts().Config["Key"] = "Old";
119 
120   CompilerInvocation B;
121   B = A;
122   B.getAnalyzerOpts().Config["Key"] = "New";
123 
124   ASSERT_EQ(A.getAnalyzerOpts().Config["Key"], "Old");
125 }
126 
127 TEST(CompilerInvocationTest, CopyOnWriteConstructor) {
128   CowCompilerInvocation A;
129   A.getMutFrontendOpts().OutputFile = "x.o";
130 
131   // B's FrontendOptions are initially shared with A.
132   CowCompilerInvocation B(A);
133   EXPECT_EQ(&A.getFrontendOpts(), &B.getFrontendOpts());
134 
135   // Modifying A's FrontendOptions creates new copy, does not affect other opts.
136   A.getMutFrontendOpts().OutputFile = "y.o";
137   EXPECT_NE(&A.getFrontendOpts(), &B.getFrontendOpts());
138   EXPECT_EQ(&A.getCodeGenOpts(), &B.getCodeGenOpts());
139 
140   // The new copy reflects the modification, old instance remains unchanged.
141   EXPECT_EQ(A.getFrontendOpts().OutputFile, "y.o");
142   EXPECT_EQ(B.getFrontendOpts().OutputFile, "x.o");
143 }
144 
145 TEST(CompilerInvocationTest, CopyOnWriteAssignment) {
146   CowCompilerInvocation A;
147   A.getMutFrontendOpts().OutputFile = "x.o";
148 
149   // B's FrontendOptions are initially independent of A.
150   CowCompilerInvocation B;
151   EXPECT_NE(&A.getFrontendOpts(), &B.getFrontendOpts());
152 
153   // B's FrontendOptions are shared with A after assignment.
154   B = A;
155   EXPECT_EQ(&A.getFrontendOpts(), &B.getFrontendOpts());
156 
157   // Modifying A's FrontendOptions creates new copy, does not affect other opts.
158   A.getMutFrontendOpts().OutputFile = "y.o";
159   EXPECT_NE(&A.getFrontendOpts(), &B.getFrontendOpts());
160   EXPECT_EQ(&A.getCodeGenOpts(), &B.getCodeGenOpts());
161 
162   // The new copy reflects the modification, old instance remains unchanged.
163   EXPECT_EQ(A.getFrontendOpts().OutputFile, "y.o");
164   EXPECT_EQ(B.getFrontendOpts().OutputFile, "x.o");
165 }
166 
167 // Boolean option with a keypath that defaults to true.
168 // The only flag with a negative spelling can set the keypath to false.
169 
170 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) {
171   const char *Args[] = {""};
172 
173   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
174   ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
175 
176   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
177 
178   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file"))));
179 }
180 
181 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) {
182   const char *Args[] = {"-fno-temp-file"};
183 
184   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
185   ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary);
186 
187   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
188 
189   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file")));
190 }
191 
192 TEST_F(CommandLineTest, CC1FlagPresentWhenDoingRoundTrip) {
193   const char *Args[] = {"-cc1", "-round-trip-args"};
194 
195   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
196 
197   ASSERT_THAT(std::string(Invocation.getCodeGenOpts().CmdArgs.begin(),
198                           Invocation.getCodeGenOpts().CmdArgs.end()),
199               StartsWith("-cc1"));
200 }
201 
202 TEST_F(CommandLineTest, CC1FlagPresentWhenNotDoingRoundTrip) {
203   const char *Args[] = {"-cc1", "-no-round-trip-args"};
204 
205   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
206 
207   ASSERT_THAT(std::string(Invocation.getCodeGenOpts().CmdArgs.begin(),
208                           Invocation.getCodeGenOpts().CmdArgs.end()),
209               StartsWith("-cc1"));
210 }
211 
212 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) {
213   const char *Args[] = {"-ftemp-file"};
214 
215   // Driver-only flag.
216   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
217   ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
218 }
219 
220 // Boolean option with a keypath that defaults to true.
221 // The flag with negative spelling can set the keypath to false.
222 // The flag with positive spelling can reset the keypath to true.
223 
224 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) {
225   const char *Args[] = {""};
226 
227   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
228   ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
229 
230   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
231   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
232   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-autolink"))));
233 }
234 
235 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) {
236   const char *Args[] = {"-fno-autolink"};
237 
238   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
239   ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink);
240 
241   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
242   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-autolink")));
243   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
244 }
245 
246 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) {
247   const char *Args[] = {"-fautolink"};
248 
249   // Driver-only flag.
250   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
251   ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
252 }
253 
254 // Boolean option with a keypath that defaults to false.
255 // The flag with negative spelling can set the keypath to true.
256 // The flag with positive spelling can reset the keypath to false.
257 
258 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) {
259   const char *Args[] = {""};
260 
261   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
262   ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
263 
264   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
265   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
266   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-inline-line-tables"))));
267 }
268 
269 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) {
270   const char *Args[] = {"-gno-inline-line-tables"};
271 
272   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
273   ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables);
274 
275   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
276   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gno-inline-line-tables")));
277   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
278 }
279 
280 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) {
281   const char *Args[] = {"-ginline-line-tables"};
282 
283   // Driver-only flag.
284   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
285   ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
286 }
287 
288 // Boolean option with a keypath that defaults to false.
289 // The flag with positive spelling can set the keypath to true.
290 // The flag with negative spelling can reset the keypath to false.
291 
292 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) {
293   const char *Args[] = {""};
294 
295   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
296   ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
297 
298   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
299   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gcodeview-ghash"))));
300   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
301 }
302 
303 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) {
304   const char *Args[] = {"-gcodeview-ghash"};
305 
306   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
307   ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash);
308 
309   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
310   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gcodeview-ghash")));
311   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
312 }
313 
314 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) {
315   const char *Args[] = {"-gno-codeview-ghash"};
316 
317   // Driver-only flag.
318   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
319   ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
320 }
321 
322 // Boolean option with a keypath that defaults to an arbitrary expression.
323 // The flag with positive spelling can set the keypath to true.
324 // The flag with negative spelling can set the keypath to false.
325 
326 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) {
327   const char *Args = {""};
328 
329   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
330   ASSERT_EQ(Invocation.getCodeGenOpts().ClearASTBeforeBackend, false);
331 
332   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
333 
334   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-no-clear-ast-before-backend"))));
335   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-clear-ast-before-backend"))));
336 }
337 
338 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentChange) {
339   const char *Args[] = {"-clear-ast-before-backend"};
340 
341   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
342   ASSERT_EQ(Invocation.getCodeGenOpts().ClearASTBeforeBackend, true);
343 
344   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
345   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-clear-ast-before-backend")));
346   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-no-clear-ast-before-backend"))));
347 }
348 
349 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentReset) {
350   const char *Args[] = {"-no-clear-ast-before-backend"};
351 
352   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
353   ASSERT_EQ(Invocation.getCodeGenOpts().ClearASTBeforeBackend, false);
354 
355   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
356   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-no-clear-ast-before-backend"))));
357   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-clear-ast-before-backend"))));
358 }
359 
360 // Boolean option that gets the CC1Option flag from a let statement (which
361 // is applied **after** the record is defined):
362 //
363 //   let Flags = [CC1Option] in {
364 //     defm option : BoolOption<...>;
365 //   }
366 
367 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNone) {
368   const char *Args[] = {""};
369 
370   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
371   ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
372 
373   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
374 
375   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
376   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
377 }
378 
379 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) {
380   const char *Args[] = {"-fdebug-pass-manager"};
381 
382   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
383   ASSERT_TRUE(Invocation.getCodeGenOpts().DebugPassManager);
384 
385   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
386 
387   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fdebug-pass-manager"), 1));
388   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
389 }
390 
391 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNeg) {
392   const char *Args[] = {"-fno-debug-pass-manager"};
393 
394   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
395   ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
396 
397   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
398 
399   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
400   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
401 }
402 
403 TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) {
404   const char *Args[] = {"-fmodules-strict-context-hash"};
405 
406   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
407 
408   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
409 
410   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash")));
411 }
412 
413 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) {
414   const char *TripleCStr = "i686-apple-darwin9";
415   const char *Args[] = {"-triple", TripleCStr};
416 
417   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
418 
419   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
420 
421   ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr)));
422 }
423 
424 TEST_F(CommandLineTest,  CanGenerateCC1CommandLineSeparateRequiredPresent) {
425   const std::string DefaultTriple =
426       llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
427   const char *Args[] = {"-triple", DefaultTriple.c_str()};
428 
429   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
430 
431   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
432 
433   // Triple should always be emitted even if it is the default
434   ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
435 }
436 
437 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) {
438   const std::string DefaultTriple =
439       llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
440   const char *Args[] = {""};
441 
442   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
443 
444   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
445 
446   // Triple should always be emitted even if it is the default
447   ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
448 }
449 
450 TEST_F(CommandLineTest, SeparateEnumNonDefault) {
451   const char *Args[] = {"-mrelocation-model", "static"};
452 
453   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
454   ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static);
455 
456   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
457 
458   // Non default relocation model.
459   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model")));
460   ASSERT_THAT(GeneratedArgs, Contains(StrEq("static")));
461   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static"))));
462 }
463 
464 TEST_F(CommandLineTest, SeparateEnumDefault) {
465   const char *Args[] = {"-mrelocation-model", "pic"};
466 
467   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
468   ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_);
469 
470   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
471 
472   // Default relocation model.
473   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model"))));
474   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic"))));
475   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic"))));
476 }
477 
478 TEST_F(CommandLineTest, JoinedEnumNonDefault) {
479   const char *Args[] = {"-fobjc-dispatch-method=non-legacy"};
480 
481   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
482   ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
483             CodeGenOptions::NonLegacy);
484 
485   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
486 
487   ASSERT_THAT(GeneratedArgs,
488               Contains(StrEq("-fobjc-dispatch-method=non-legacy")));
489   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
490   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy"))));
491 }
492 
493 TEST_F(CommandLineTest, JoinedEnumDefault) {
494   const char *Args[] = {"-fobjc-dispatch-method=legacy"};
495 
496   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
497   ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
498             CodeGenOptions::Legacy);
499 
500   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
501 
502   ASSERT_THAT(GeneratedArgs,
503               Not(Contains(StrEq("-fobjc-dispatch-method=legacy"))));
504   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
505   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy"))));
506 }
507 
508 TEST_F(CommandLineTest, StringVectorEmpty) {
509   const char *Args[] = {""};
510 
511   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
512   ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty());
513 
514   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
515 
516   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file"))));
517 }
518 
519 TEST_F(CommandLineTest, StringVectorSingle) {
520   const char *Args[] = {"-fmodule-map-file=a"};
521 
522   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
523   ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles,
524             std::vector<std::string>({"a"}));
525 
526   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
527 
528   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
529   ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 1));
530 }
531 
532 TEST_F(CommandLineTest, StringVectorMultiple) {
533   const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"};
534 
535   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
536   ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles ==
537               std::vector<std::string>({"a", "b"}));
538 
539   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
540 
541   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
542   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=b"), 1));
543   ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 2));
544 }
545 
546 // CommaJoined option with MarshallingInfoStringVector.
547 
548 TEST_F(CommandLineTest, StringVectorCommaJoinedNone) {
549   const char *Args[] = {""};
550 
551   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
552   ASSERT_TRUE(Invocation.getLangOpts().CommentOpts.BlockCommandNames.empty());
553 
554   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
555 
556   ASSERT_THAT(GeneratedArgs,
557               Not(Contains(HasSubstr("-fcomment-block-commands"))));
558 }
559 
560 TEST_F(CommandLineTest, StringVectorCommaJoinedSingle) {
561   const char *Args[] = {"-fcomment-block-commands=x,y"};
562 
563   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
564   ASSERT_EQ(Invocation.getLangOpts().CommentOpts.BlockCommandNames,
565             std::vector<std::string>({"x", "y"}));
566 
567   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
568 
569   ASSERT_THAT(GeneratedArgs,
570               ContainsN(StrEq("-fcomment-block-commands=x,y"), 1));
571 }
572 
573 TEST_F(CommandLineTest, StringVectorCommaJoinedMultiple) {
574   const char *Args[] = {"-fcomment-block-commands=x,y",
575                         "-fcomment-block-commands=a,b"};
576 
577   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
578   ASSERT_EQ(Invocation.getLangOpts().CommentOpts.BlockCommandNames,
579             std::vector<std::string>({"x", "y", "a", "b"}));
580 
581   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
582 
583   ASSERT_THAT(GeneratedArgs,
584               ContainsN(StrEq("-fcomment-block-commands=x,y,a,b"), 1));
585 }
586 
587 // A flag that should be parsed only if a condition is met.
588 
589 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagNotPresent) {
590   const char *Args[] = {""};
591 
592   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
593 
594   ASSERT_FALSE(Diags->hasErrorOccurred());
595   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsDevice);
596   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsHost);
597   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(), LangOptions::SYCL_None);
598 
599   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
600 
601   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl"))));
602   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
603 }
604 
605 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagPresent) {
606   const char *Args[] = {"-sycl-std=2017"};
607 
608   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
609 
610   ASSERT_FALSE(Diags->hasErrorOccurred());
611   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsDevice);
612   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsHost);
613   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(), LangOptions::SYCL_None);
614 
615   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
616 
617   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-device"))));
618   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
619   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
620 }
621 
622 TEST_F(CommandLineTest, ConditionalParsingIfNonsenseSyclStdArg) {
623   const char *Args[] = {"-fsycl-is-device", "-sycl-std=garbage"};
624 
625   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
626 
627   ASSERT_TRUE(Diags->hasErrorOccurred());
628   ASSERT_TRUE(Invocation.getLangOpts().SYCLIsDevice);
629   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsHost);
630   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(), LangOptions::SYCL_None);
631 
632   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
633 
634   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
635   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
636   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
637 }
638 
639 TEST_F(CommandLineTest, ConditionalParsingIfOddSyclStdArg1) {
640   const char *Args[] = {"-fsycl-is-device", "-sycl-std=121"};
641 
642   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
643 
644   ASSERT_FALSE(Diags->hasErrorOccurred());
645   ASSERT_TRUE(Invocation.getLangOpts().SYCLIsDevice);
646   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsHost);
647   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(), LangOptions::SYCL_2017);
648 
649   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
650 
651   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
652   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
653   ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=2017")));
654 }
655 
656 TEST_F(CommandLineTest, ConditionalParsingIfOddSyclStdArg2) {
657   const char *Args[] = {"-fsycl-is-device", "-sycl-std=1.2.1"};
658 
659   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
660 
661   ASSERT_FALSE(Diags->hasErrorOccurred());
662   ASSERT_TRUE(Invocation.getLangOpts().SYCLIsDevice);
663   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsHost);
664   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(), LangOptions::SYCL_2017);
665 
666   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
667 
668   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
669   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
670   ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=2017")));
671 }
672 
673 TEST_F(CommandLineTest, ConditionalParsingIfOddSyclStdArg3) {
674   const char *Args[] = {"-fsycl-is-device", "-sycl-std=sycl-1.2.1"};
675 
676   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
677 
678   ASSERT_FALSE(Diags->hasErrorOccurred());
679   ASSERT_TRUE(Invocation.getLangOpts().SYCLIsDevice);
680   ASSERT_FALSE(Invocation.getLangOpts().SYCLIsHost);
681   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(), LangOptions::SYCL_2017);
682 
683   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
684 
685   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
686   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
687   ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=2017")));
688 }
689 
690 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresentHost) {
691   const char *Args[] = {"-fsycl-is-host"};
692 
693   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
694 
695   ASSERT_FALSE(Diags->hasErrorOccurred());
696   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(),
697             LangOptions::SYCL_Default);
698 
699   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
700 
701   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-host")));
702   ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=")));
703 }
704 
705 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresentDevice) {
706   const char *Args[] = {"-fsycl-is-device"};
707 
708   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
709 
710   ASSERT_FALSE(Diags->hasErrorOccurred());
711   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(),
712             LangOptions::SYCL_Default);
713 
714   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
715 
716   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
717   ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=")));
718 }
719 
720 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagPresent) {
721   const char *Args[] = {"-fsycl-is-device", "-sycl-std=2017"};
722 
723   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
724 
725   ASSERT_FALSE(Diags->hasErrorOccurred());
726   ASSERT_EQ(Invocation.getLangOpts().getSYCLVersion(), LangOptions::SYCL_2017);
727 
728   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
729 
730   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
731   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-sycl-std=2017")));
732 }
733 
734 // Wide integer option.
735 
736 TEST_F(CommandLineTest, WideIntegerHighValue) {
737   const char *Args[] = {"-fbuild-session-timestamp=1609827494445723662"};
738 
739   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
740 
741   ASSERT_FALSE(Diags->hasErrorOccurred());
742   ASSERT_EQ(Invocation.getHeaderSearchOpts().BuildSessionTimestamp,
743             1609827494445723662ull);
744 }
745 
746 // Tree of boolean options that can be (directly or transitively) implied by
747 // their parent:
748 //
749 //   * -cl-unsafe-math-optimizations
750 //     * -cl-mad-enable
751 //     * -funsafe-math-optimizations
752 //       * -freciprocal-math
753 
754 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) {
755   const char *Args[] = {""};
756 
757   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
758   ASSERT_FALSE(Invocation.getLangOpts().CLUnsafeMath);
759   ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
760   ASSERT_FALSE(Invocation.getLangOpts().UnsafeFPMath);
761   ASSERT_FALSE(Invocation.getLangOpts().AllowRecip);
762 
763   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
764 
765   // Not generated - missing.
766   ASSERT_THAT(GeneratedArgs,
767               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
768   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
769   ASSERT_THAT(GeneratedArgs,
770               Not(Contains(StrEq("-funsafe-math-optimizations"))));
771   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
772 }
773 
774 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) {
775   const char *Args[] = {"-cl-unsafe-math-optimizations"};
776 
777   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
778   // Explicitly provided root flag.
779   ASSERT_TRUE(Invocation.getLangOpts().CLUnsafeMath);
780   // Directly implied by explicitly provided root flag.
781   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
782   ASSERT_TRUE(Invocation.getLangOpts().UnsafeFPMath);
783   // Transitively implied by explicitly provided root flag.
784   ASSERT_TRUE(Invocation.getLangOpts().AllowRecip);
785 
786   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
787 
788   // Generated - explicitly provided.
789   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
790   // Not generated - implied by the generated root flag.
791   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
792   ASSERT_THAT(GeneratedArgs,
793               Not(Contains(StrEq("-funsafe-math-optimizations"))));
794   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
795 }
796 
797 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) {
798   const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable",
799                         "-funsafe-math-optimizations", "-freciprocal-math"};
800 
801   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
802   ASSERT_TRUE(Invocation.getLangOpts().CLUnsafeMath);
803   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
804   ASSERT_TRUE(Invocation.getLangOpts().UnsafeFPMath);
805   ASSERT_TRUE(Invocation.getLangOpts().AllowRecip);
806 
807   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
808 
809   // Generated - explicitly provided.
810   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
811   // Not generated - implied by their generated parent.
812   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
813   ASSERT_THAT(GeneratedArgs,
814               Not(Contains(StrEq("-funsafe-math-optimizations"))));
815   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
816 }
817 
818 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) {
819   const char *Args[] = {"-cl-mad-enable", "-funsafe-math-optimizations",
820                         "-freciprocal-math"};
821 
822   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
823   ASSERT_FALSE(Invocation.getLangOpts().CLUnsafeMath);
824   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
825   ASSERT_TRUE(Invocation.getLangOpts().UnsafeFPMath);
826   ASSERT_TRUE(Invocation.getLangOpts().AllowRecip);
827 
828   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
829   // Not generated - missing.
830   ASSERT_THAT(GeneratedArgs,
831               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
832   // Generated - explicitly provided.
833   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
834   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-funsafe-math-optimizations")));
835   // Not generated - implied by its generated parent.
836   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
837 }
838 
839 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) {
840   const char *Args[] = {"-cl-mad-enable", "-funsafe-math-optimizations"};
841 
842   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
843 
844   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
845 
846   // Present options that were not implied are generated.
847   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
848   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-funsafe-math-optimizations")));
849 }
850 
851 // Diagnostic option.
852 
853 TEST_F(CommandLineTest, DiagnosticOptionPresent) {
854   const char *Args[] = {"-verify=xyz"};
855 
856   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
857 
858   ASSERT_EQ(Invocation.getDiagnosticOpts().VerifyPrefixes,
859             std::vector<std::string>({"xyz"}));
860 
861   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
862 
863   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-verify=xyz"), 1));
864 }
865 
866 // Option default depends on language standard.
867 
868 TEST_F(CommandLineTest, DigraphsImplied) {
869   const char *Args[] = {""};
870 
871   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
872   ASSERT_TRUE(Invocation.getLangOpts().Digraphs);
873 
874   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
875   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-digraphs"))));
876   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
877 }
878 
879 TEST_F(CommandLineTest, DigraphsDisabled) {
880   const char *Args[] = {"-fno-digraphs"};
881 
882   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
883   ASSERT_FALSE(Invocation.getLangOpts().Digraphs);
884 
885   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
886   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-digraphs")));
887   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
888 }
889 
890 TEST_F(CommandLineTest, DigraphsNotImplied) {
891   const char *Args[] = {"-std=c89"};
892 
893   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
894   ASSERT_FALSE(Invocation.getLangOpts().Digraphs);
895 
896   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
897   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-digraphs"))));
898   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
899 }
900 
901 TEST_F(CommandLineTest, DigraphsEnabled) {
902   const char *Args[] = {"-std=c89", "-fdigraphs"};
903 
904   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
905   ASSERT_TRUE(Invocation.getLangOpts().Digraphs);
906 
907   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
908   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fdigraphs")));
909 }
910 
911 struct DummyModuleFileExtension
912     : public llvm::RTTIExtends<DummyModuleFileExtension, ModuleFileExtension> {
913   static char ID;
914 
915   ModuleFileExtensionMetadata getExtensionMetadata() const override {
916     return {};
917   };
918 
919   void hashExtension(ExtensionHashBuilder &HBuilder) const override {}
920 
921   std::unique_ptr<ModuleFileExtensionWriter>
922   createExtensionWriter(ASTWriter &Writer) override {
923     return {};
924   }
925 
926   std::unique_ptr<ModuleFileExtensionReader>
927   createExtensionReader(const ModuleFileExtensionMetadata &Metadata,
928                         ASTReader &Reader, serialization::ModuleFile &Mod,
929                         const llvm::BitstreamCursor &Stream) override {
930     return {};
931   }
932 };
933 
934 char DummyModuleFileExtension::ID = 0;
935 
936 TEST_F(CommandLineTest, TestModuleFileExtension) {
937   const char *Args[] = {"-ftest-module-file-extension=first:2:1:0:first",
938                         "-ftest-module-file-extension=second:3:2:1:second"};
939 
940   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
941   ASSERT_THAT(Invocation.getFrontendOpts().ModuleFileExtensions.size(), 2);
942 
943   // Exercise the check that only serializes instances of
944   // TestModuleFileExtension by providing an instance of another
945   // ModuleFileExtension subclass.
946   Invocation.getFrontendOpts().ModuleFileExtensions.push_back(
947       std::make_shared<DummyModuleFileExtension>());
948 
949   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
950 
951   ASSERT_THAT(GeneratedArgs,
952               ContainsN(HasSubstr("-ftest-module-file-extension="), 2));
953   ASSERT_THAT(
954       GeneratedArgs,
955       Contains(StrEq("-ftest-module-file-extension=first:2:1:0:first")));
956   ASSERT_THAT(
957       GeneratedArgs,
958       Contains(StrEq("-ftest-module-file-extension=second:3:2:1:second")));
959 }
960 
961 TEST_F(CommandLineTest, RoundTrip) {
962   // Testing one marshalled and one manually generated option from each
963   // CompilerInvocation member.
964   const char *Args[] = {
965       "-round-trip-args",
966       // LanguageOptions
967       "-std=c17",
968       "-fmax-tokens=10",
969       // TargetOptions
970       "-target-sdk-version=1.2.3",
971       "-meabi",
972       "4",
973       // DiagnosticOptions
974       "-Wundef-prefix=XY",
975       "-fdiagnostics-format",
976       "clang",
977       // HeaderSearchOptions
978       "-stdlib=libc++",
979       "-fimplicit-module-maps",
980       // PreprocessorOptions
981       "-DXY=AB",
982       "-include-pch",
983       "a.pch",
984       // AnalyzerOptions
985       "-analyzer-config",
986       "ctu-import-threshold=42",
987       "-unoptimized-cfg",
988       // MigratorOptions (no manually handled arguments)
989       "-no-ns-alloc-error",
990       // CodeGenOptions
991       "-debug-info-kind=limited",
992       "-debug-info-macro",
993       // DependencyOutputOptions
994       "--show-includes",
995       "-H",
996       // FileSystemOptions (no manually handled arguments)
997       "-working-directory",
998       "folder",
999       // FrontendOptions
1000       "-load",
1001       "plugin",
1002       "-ast-merge",
1003       // PreprocessorOutputOptions
1004       "-dD",
1005       "-CC",
1006   };
1007 
1008   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
1009 
1010   ASSERT_TRUE(Invocation.getLangOpts().C17);
1011   ASSERT_EQ(Invocation.getLangOpts().MaxTokens, 10u);
1012 
1013   ASSERT_EQ(Invocation.getTargetOpts().SDKVersion, llvm::VersionTuple(1, 2, 3));
1014   ASSERT_EQ(Invocation.getTargetOpts().EABIVersion, EABI::EABI4);
1015 
1016   ASSERT_THAT(Invocation.getDiagnosticOpts().UndefPrefixes,
1017               Contains(StrEq("XY")));
1018   ASSERT_EQ(Invocation.getDiagnosticOpts().getFormat(),
1019             TextDiagnosticFormat::Clang);
1020 
1021   ASSERT_TRUE(Invocation.getHeaderSearchOpts().UseLibcxx);
1022   ASSERT_TRUE(Invocation.getHeaderSearchOpts().ImplicitModuleMaps);
1023 
1024   ASSERT_THAT(Invocation.getPreprocessorOpts().Macros,
1025               Contains(std::make_pair(std::string("XY=AB"), false)));
1026   ASSERT_EQ(Invocation.getPreprocessorOpts().ImplicitPCHInclude, "a.pch");
1027 
1028   ASSERT_EQ(Invocation.getAnalyzerOpts().Config["ctu-import-threshold"], "42");
1029   ASSERT_TRUE(Invocation.getAnalyzerOpts().UnoptimizedCFG);
1030 
1031   ASSERT_TRUE(Invocation.getMigratorOpts().NoNSAllocReallocError);
1032 
1033   ASSERT_EQ(Invocation.getCodeGenOpts().getDebugInfo(),
1034             codegenoptions::DebugInfoKind::LimitedDebugInfo);
1035   ASSERT_TRUE(Invocation.getCodeGenOpts().MacroDebugInfo);
1036 
1037   ASSERT_EQ(Invocation.getDependencyOutputOpts().ShowIncludesDest,
1038             ShowIncludesDestination::Stdout);
1039   ASSERT_TRUE(Invocation.getDependencyOutputOpts().ShowHeaderIncludes);
1040 }
1041 
1042 TEST_F(CommandLineTest, PluginArgsRoundTripDeterminism) {
1043   const char *Args[] = {
1044       "-plugin-arg-blink-gc-plugin", "no-members-in-stack-allocated",
1045       "-plugin-arg-find-bad-constructs", "checked-ptr-as-trivial-member",
1046       "-plugin-arg-find-bad-constructs", "check-ipc",
1047       // Enable round-trip to ensure '-plugin-arg' generation is deterministic.
1048       "-round-trip-args"};
1049 
1050   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
1051 }
1052 
1053 TEST_F(CommandLineTest, WarningSuppressionMappings) {
1054   const char *Args[] = {"--warning-suppression-mappings=foo.txt"};
1055 
1056   EXPECT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
1057   EXPECT_EQ(Invocation.getDiagnosticOpts().DiagnosticSuppressionMappingsFile,
1058             "foo.txt");
1059 
1060   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
1061   EXPECT_THAT(GeneratedArgs, Contains(StrEq(Args[0])));
1062 }
1063 } // anonymous namespace
1064