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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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