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