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