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