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