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