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