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

source code of clang/unittests/Frontend/CompilerInvocationTest.cpp