1 //===-- ParsedASTTests.cpp ------------------------------------------------===// 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 // These tests cover clangd's logic to build a TU, which generally uses the APIs 10 // in ParsedAST and Preamble, via the TestTU helper. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "../../clang-tidy/ClangTidyCheck.h" 15 #include "AST.h" 16 #include "Compiler.h" 17 #include "Config.h" 18 #include "Diagnostics.h" 19 #include "Headers.h" 20 #include "ParsedAST.h" 21 #include "Preamble.h" 22 #include "SourceCode.h" 23 #include "TestFS.h" 24 #include "TestTU.h" 25 #include "TidyProvider.h" 26 #include "support/Context.h" 27 #include "clang/AST/DeclTemplate.h" 28 #include "clang/Basic/FileEntry.h" 29 #include "clang/Basic/SourceLocation.h" 30 #include "clang/Basic/SourceManager.h" 31 #include "clang/Basic/TokenKinds.h" 32 #include "clang/Tooling/Syntax/Tokens.h" 33 #include "llvm/ADT/StringRef.h" 34 #include "llvm/Testing/Annotations/Annotations.h" 35 #include "llvm/Testing/Support/Error.h" 36 #include "gmock/gmock-matchers.h" 37 #include "gmock/gmock.h" 38 #include "gtest/gtest.h" 39 #include <memory> 40 #include <string_view> 41 #include <utility> 42 #include <vector> 43 44 namespace clang { 45 namespace clangd { 46 namespace { 47 48 using ::testing::AllOf; 49 using ::testing::Contains; 50 using ::testing::ElementsAre; 51 using ::testing::ElementsAreArray; 52 using ::testing::IsEmpty; 53 54 MATCHER_P(declNamed, Name, "") { 55 if (NamedDecl *ND = dyn_cast<NamedDecl>(arg)) 56 if (ND->getName() == Name) 57 return true; 58 if (auto *Stream = result_listener->stream()) { 59 llvm::raw_os_ostream OS(*Stream); 60 arg->dump(OS); 61 } 62 return false; 63 } 64 65 MATCHER_P(declKind, Kind, "") { 66 if (NamedDecl *ND = dyn_cast<NamedDecl>(arg)) 67 if (ND->getDeclKindName() == llvm::StringRef(Kind)) 68 return true; 69 if (auto *Stream = result_listener->stream()) { 70 llvm::raw_os_ostream OS(*Stream); 71 arg->dump(OS); 72 } 73 return false; 74 } 75 76 // Matches if the Decl has template args equal to ArgName. If the decl is a 77 // NamedDecl and ArgName is an empty string it also matches. 78 MATCHER_P(withTemplateArgs, ArgName, "") { 79 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(arg)) { 80 if (const auto *Args = FD->getTemplateSpecializationArgs()) { 81 std::string SpecializationArgs; 82 // Without the PrintingPolicy "bool" will be printed as "_Bool". 83 LangOptions LO; 84 PrintingPolicy Policy(LO); 85 Policy.adjustForCPlusPlus(); 86 for (const auto &Arg : Args->asArray()) { 87 if (SpecializationArgs.size() > 0) 88 SpecializationArgs += ","; 89 SpecializationArgs += Arg.getAsType().getAsString(Policy); 90 } 91 if (Args->size() == 0) 92 return ArgName == SpecializationArgs; 93 return ArgName == "<" + SpecializationArgs + ">"; 94 } 95 } 96 if (const NamedDecl *ND = dyn_cast<NamedDecl>(arg)) 97 return printTemplateSpecializationArgs(*ND) == ArgName; 98 return false; 99 } 100 101 MATCHER_P(pragmaTrivia, P, "") { return arg.Trivia == P; } 102 103 MATCHER(eqInc, "") { 104 Inclusion Actual = testing::get<0>(arg); 105 Inclusion Expected = testing::get<1>(arg); 106 return std::tie(Actual.HashLine, Actual.Written) == 107 std::tie(Expected.HashLine, Expected.Written); 108 } 109 110 TEST(ParsedASTTest, TopLevelDecls) { 111 TestTU TU; 112 TU.HeaderCode = R"( 113 int header1(); 114 int header2; 115 )"; 116 TU.Code = R"cpp( 117 int main(); 118 template <typename> bool X = true; 119 )cpp"; 120 auto AST = TU.build(); 121 EXPECT_THAT(AST.getLocalTopLevelDecls(), 122 testing::UnorderedElementsAreArray( 123 {AllOf(declNamed("main"), declKind("Function")), 124 AllOf(declNamed("X"), declKind("VarTemplate"))})); 125 } 126 127 TEST(ParsedASTTest, DoesNotGetIncludedTopDecls) { 128 TestTU TU; 129 TU.HeaderCode = R"cpp( 130 #define LL void foo(){} 131 template<class T> 132 struct H { 133 H() {} 134 LL 135 }; 136 )cpp"; 137 TU.Code = R"cpp( 138 int main() { 139 H<int> h; 140 h.foo(); 141 } 142 )cpp"; 143 auto AST = TU.build(); 144 EXPECT_THAT(AST.getLocalTopLevelDecls(), ElementsAre(declNamed("main"))); 145 } 146 147 TEST(ParsedASTTest, DoesNotGetImplicitTemplateTopDecls) { 148 TestTU TU; 149 TU.Code = R"cpp( 150 template<typename T> 151 void f(T) {} 152 void s() { 153 f(10UL); 154 } 155 )cpp"; 156 157 auto AST = TU.build(); 158 EXPECT_THAT(AST.getLocalTopLevelDecls(), 159 ElementsAre(declNamed("f"), declNamed("s"))); 160 } 161 162 TEST(ParsedASTTest, 163 GetsExplicitInstantiationAndSpecializationTemplateTopDecls) { 164 TestTU TU; 165 TU.Code = R"cpp( 166 template <typename T> 167 void f(T) {} 168 template<> 169 void f(bool); 170 template void f(double); 171 172 template <class T> 173 struct V {}; 174 template<class T> 175 struct V<T*> {}; 176 template <> 177 struct V<bool> {}; 178 179 template<class T> 180 T foo = T(10); 181 int i = foo<int>; 182 double d = foo<double>; 183 184 template <class T> 185 int foo<T*> = 0; 186 template <> 187 int foo<bool> = 0; 188 )cpp"; 189 190 auto AST = TU.build(); 191 EXPECT_THAT( 192 AST.getLocalTopLevelDecls(), 193 ElementsAreArray({AllOf(declNamed("f"), withTemplateArgs("")), 194 AllOf(declNamed("f"), withTemplateArgs("<bool>")), 195 AllOf(declNamed("f"), withTemplateArgs("<double>")), 196 AllOf(declNamed("V"), withTemplateArgs("")), 197 AllOf(declNamed("V"), withTemplateArgs("<T *>")), 198 AllOf(declNamed("V"), withTemplateArgs("<bool>")), 199 AllOf(declNamed("foo"), withTemplateArgs("")), 200 AllOf(declNamed("i"), withTemplateArgs("")), 201 AllOf(declNamed("d"), withTemplateArgs("")), 202 AllOf(declNamed("foo"), withTemplateArgs("<T *>")), 203 AllOf(declNamed("foo"), withTemplateArgs("<bool>"))})); 204 } 205 206 TEST(ParsedASTTest, IgnoresDelayedTemplateParsing) { 207 auto TU = TestTU::withCode(R"cpp( 208 template <typename T> void xxx() { 209 int yyy = 0; 210 } 211 )cpp"); 212 TU.ExtraArgs.push_back("-fdelayed-template-parsing"); 213 auto AST = TU.build(); 214 EXPECT_EQ(Decl::Var, findUnqualifiedDecl(AST, "yyy").getKind()); 215 } 216 217 TEST(ParsedASTTest, TokensAfterPreamble) { 218 TestTU TU; 219 TU.AdditionalFiles["foo.h"] = R"( 220 int foo(); 221 )"; 222 TU.Code = R"cpp( 223 #include "foo.h" 224 first_token; 225 void test() { 226 // error-ok: invalid syntax, just examining token stream 227 } 228 last_token 229 )cpp"; 230 auto AST = TU.build(); 231 const syntax::TokenBuffer &T = AST.getTokens(); 232 const auto &SM = AST.getSourceManager(); 233 234 ASSERT_GT(T.expandedTokens().size(), 2u); 235 // Check first token after the preamble. 236 EXPECT_EQ(T.expandedTokens().front().text(SM), "first_token"); 237 // Last token is always 'eof'. 238 EXPECT_EQ(T.expandedTokens().back().kind(), tok::eof); 239 // Check the token before 'eof'. 240 EXPECT_EQ(T.expandedTokens().drop_back().back().text(SM), "last_token"); 241 242 // The spelled tokens for the main file should have everything. 243 auto Spelled = T.spelledTokens(SM.getMainFileID()); 244 ASSERT_FALSE(Spelled.empty()); 245 EXPECT_EQ(Spelled.front().kind(), tok::hash); 246 EXPECT_EQ(Spelled.back().text(SM), "last_token"); 247 } 248 249 TEST(ParsedASTTest, NoCrashOnTokensWithTidyCheck) { 250 TestTU TU; 251 // this check runs the preprocessor, we need to make sure it does not break 252 // our recording logic. 253 TU.ClangTidyProvider = addTidyChecks("modernize-use-trailing-return-type"); 254 TU.Code = "inline int foo() {}"; 255 256 auto AST = TU.build(); 257 const syntax::TokenBuffer &T = AST.getTokens(); 258 const auto &SM = AST.getSourceManager(); 259 260 ASSERT_GT(T.expandedTokens().size(), 7u); 261 // Check first token after the preamble. 262 EXPECT_EQ(T.expandedTokens().front().text(SM), "inline"); 263 // Last token is always 'eof'. 264 EXPECT_EQ(T.expandedTokens().back().kind(), tok::eof); 265 // Check the token before 'eof'. 266 EXPECT_EQ(T.expandedTokens().drop_back().back().text(SM), "}"); 267 } 268 269 TEST(ParsedASTTest, CanBuildInvocationWithUnknownArgs) { 270 MockFS FS; 271 FS.Files = {{testPath("foo.cpp"), "void test() {}"}}; 272 // Unknown flags should not prevent a build of compiler invocation. 273 ParseInputs Inputs; 274 Inputs.TFS = &FS; 275 Inputs.CompileCommand.CommandLine = {"clang", "-fsome-unknown-flag", 276 testPath("foo.cpp")}; 277 IgnoreDiagnostics IgnoreDiags; 278 EXPECT_NE(buildCompilerInvocation(Inputs, IgnoreDiags), nullptr); 279 280 // Unknown forwarded to -cc1 should not a failure either. 281 Inputs.CompileCommand.CommandLine = { 282 "clang", "-Xclang", "-fsome-unknown-flag", testPath("foo.cpp")}; 283 EXPECT_NE(buildCompilerInvocation(Inputs, IgnoreDiags), nullptr); 284 } 285 286 TEST(ParsedASTTest, CollectsMainFileMacroExpansions) { 287 llvm::Annotations TestCase(R"cpp( 288 #define ^MACRO_ARGS(X, Y) X Y 289 // - preamble ends 290 ^ID(int A); 291 // Macro arguments included. 292 ^MACRO_ARGS(^MACRO_ARGS(^MACRO_EXP(int), E), ^ID(= 2)); 293 294 // Macro names inside other macros not included. 295 #define ^MACRO_ARGS2(X, Y) X Y 296 #define ^FOO BAR 297 #define ^BAR 1 298 int F = ^FOO; 299 300 // Macros from token concatenations not included. 301 #define ^CONCAT(X) X##A() 302 #define ^PREPEND(X) MACRO##X() 303 #define ^MACROA() 123 304 int G = ^CONCAT(MACRO); 305 int H = ^PREPEND(A); 306 307 // Macros included not from preamble not included. 308 #include "foo.inc" 309 310 int printf(const char*, ...); 311 void exit(int); 312 #define ^assert(COND) if (!(COND)) { printf("%s", #COND); exit(0); } 313 314 void test() { 315 // Includes macro expansions in arguments that are expressions 316 ^assert(0 <= ^BAR); 317 } 318 319 #ifdef ^UNDEFINED 320 #endif 321 322 #define ^MULTIPLE_DEFINITION 1 323 #undef ^MULTIPLE_DEFINITION 324 325 #define ^MULTIPLE_DEFINITION 2 326 #undef ^MULTIPLE_DEFINITION 327 )cpp"); 328 auto TU = TestTU::withCode(TestCase.code()); 329 TU.HeaderCode = R"cpp( 330 #define ID(X) X 331 #define MACRO_EXP(X) ID(X) 332 MACRO_EXP(int B); 333 )cpp"; 334 TU.AdditionalFiles["foo.inc"] = R"cpp( 335 int C = ID(1); 336 #define DEF 1 337 int D = DEF; 338 )cpp"; 339 ParsedAST AST = TU.build(); 340 std::vector<size_t> MacroExpansionPositions; 341 for (const auto &SIDToRefs : AST.getMacros().MacroRefs) { 342 for (const auto &R : SIDToRefs.second) 343 MacroExpansionPositions.push_back(R.StartOffset); 344 } 345 for (const auto &R : AST.getMacros().UnknownMacros) 346 MacroExpansionPositions.push_back(R.StartOffset); 347 EXPECT_THAT(MacroExpansionPositions, 348 testing::UnorderedElementsAreArray(TestCase.points())); 349 } 350 351 MATCHER_P(withFileName, Inc, "") { return arg.FileName == Inc; } 352 353 TEST(ParsedASTTest, PatchesAdditionalIncludes) { 354 llvm::StringLiteral ModifiedContents = R"cpp( 355 #include "baz.h" 356 #include "foo.h" 357 #include "sub/aux.h" 358 void bar() { 359 foo(); 360 baz(); 361 aux(); 362 })cpp"; 363 // Build expected ast with symbols coming from headers. 364 TestTU TU; 365 TU.Filename = "foo.cpp"; 366 TU.AdditionalFiles["foo.h"] = "void foo();"; 367 TU.AdditionalFiles["sub/baz.h"] = "void baz();"; 368 TU.AdditionalFiles["sub/aux.h"] = "void aux();"; 369 TU.ExtraArgs = {"-I" + testPath("sub")}; 370 TU.Code = ModifiedContents.str(); 371 auto ExpectedAST = TU.build(); 372 373 // Build preamble with no includes. 374 TU.Code = ""; 375 StoreDiags Diags; 376 MockFS FS; 377 auto Inputs = TU.inputs(FS); 378 auto CI = buildCompilerInvocation(Inputs, Diags); 379 auto EmptyPreamble = 380 buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr); 381 ASSERT_TRUE(EmptyPreamble); 382 EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, IsEmpty()); 383 384 // Now build an AST using empty preamble and ensure patched includes worked. 385 TU.Code = ModifiedContents.str(); 386 Inputs = TU.inputs(FS); 387 auto PatchedAST = ParsedAST::build(testPath("foo.cpp"), Inputs, std::move(CI), 388 {}, EmptyPreamble); 389 ASSERT_TRUE(PatchedAST); 390 391 // Ensure source location information is correct, including resolved paths. 392 EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes, 393 testing::Pointwise( 394 eqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes)); 395 // Ensure file proximity signals are correct. 396 auto &SM = PatchedAST->getSourceManager(); 397 auto &FM = SM.getFileManager(); 398 // Copy so that we can use operator[] to get the children. 399 IncludeStructure Includes = PatchedAST->getIncludeStructure(); 400 auto MainFE = FM.getOptionalFileRef(testPath("foo.cpp")); 401 ASSERT_TRUE(MainFE); 402 auto MainID = Includes.getID(*MainFE); 403 auto AuxFE = FM.getOptionalFileRef(testPath("sub/aux.h")); 404 ASSERT_TRUE(AuxFE); 405 auto AuxID = Includes.getID(*AuxFE); 406 EXPECT_THAT(Includes.IncludeChildren[*MainID], Contains(*AuxID)); 407 } 408 409 TEST(ParsedASTTest, PatchesDeletedIncludes) { 410 TestTU TU; 411 TU.Filename = "foo.cpp"; 412 TU.Code = ""; 413 auto ExpectedAST = TU.build(); 414 415 // Build preamble with no includes. 416 TU.Code = R"cpp(#include <foo.h>)cpp"; 417 StoreDiags Diags; 418 MockFS FS; 419 auto Inputs = TU.inputs(FS); 420 auto CI = buildCompilerInvocation(Inputs, Diags); 421 auto BaselinePreamble = 422 buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr); 423 ASSERT_TRUE(BaselinePreamble); 424 EXPECT_THAT(BaselinePreamble->Includes.MainFileIncludes, 425 ElementsAre(testing::Field(&Inclusion::Written, "<foo.h>"))); 426 427 // Now build an AST using additional includes and check that locations are 428 // correctly parsed. 429 TU.Code = ""; 430 Inputs = TU.inputs(FS); 431 auto PatchedAST = ParsedAST::build(testPath("foo.cpp"), Inputs, std::move(CI), 432 {}, BaselinePreamble); 433 ASSERT_TRUE(PatchedAST); 434 435 // Ensure source location information is correct. 436 EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes, 437 testing::Pointwise( 438 eqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes)); 439 // Ensure file proximity signals are correct. 440 auto &SM = ExpectedAST.getSourceManager(); 441 auto &FM = SM.getFileManager(); 442 // Copy so that we can getOrCreateID(). 443 IncludeStructure Includes = ExpectedAST.getIncludeStructure(); 444 auto MainFE = FM.getFileRef(testPath("foo.cpp")); 445 ASSERT_THAT_EXPECTED(MainFE, llvm::Succeeded()); 446 auto MainID = Includes.getOrCreateID(*MainFE); 447 auto &PatchedFM = PatchedAST->getSourceManager().getFileManager(); 448 IncludeStructure PatchedIncludes = PatchedAST->getIncludeStructure(); 449 auto PatchedMainFE = PatchedFM.getFileRef(testPath("foo.cpp")); 450 ASSERT_THAT_EXPECTED(PatchedMainFE, llvm::Succeeded()); 451 auto PatchedMainID = PatchedIncludes.getOrCreateID(*PatchedMainFE); 452 EXPECT_EQ(Includes.includeDepth(MainID)[MainID], 453 PatchedIncludes.includeDepth(PatchedMainID)[PatchedMainID]); 454 } 455 456 // Returns Code guarded by #ifndef guards 457 std::string guard(llvm::StringRef Code) { 458 static int GuardID = 0; 459 std::string GuardName = ("GUARD_" + llvm::Twine(++GuardID)).str(); 460 return llvm::formatv("#ifndef {0}\n#define {0}\n{1}\n#endif\n", GuardName, 461 Code); 462 } 463 464 std::string once(llvm::StringRef Code) { 465 return llvm::formatv("#pragma once\n{0}\n", Code); 466 } 467 468 bool mainIsGuarded(const ParsedAST &AST) { 469 const auto &SM = AST.getSourceManager(); 470 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID()); 471 return AST.getPreprocessor() 472 .getHeaderSearchInfo() 473 .isFileMultipleIncludeGuarded(*MainFE); 474 } 475 476 MATCHER_P(diag, Desc, "") { 477 return llvm::StringRef(arg.Message).contains(Desc); 478 } 479 480 // Check our understanding of whether the main file is header guarded or not. 481 TEST(ParsedASTTest, HeaderGuards) { 482 TestTU TU; 483 TU.ImplicitHeaderGuard = false; 484 485 TU.Code = ";"; 486 EXPECT_FALSE(mainIsGuarded(TU.build())); 487 488 TU.Code = guard(";"); 489 EXPECT_TRUE(mainIsGuarded(TU.build())); 490 491 TU.Code = once(";"); 492 EXPECT_TRUE(mainIsGuarded(TU.build())); 493 494 TU.Code = R"cpp( 495 ; 496 #pragma once 497 )cpp"; 498 EXPECT_FALSE(mainIsGuarded(TU.build())); // FIXME: true 499 500 TU.Code = R"cpp( 501 ; 502 #ifndef GUARD 503 #define GUARD 504 ; 505 #endif 506 )cpp"; 507 EXPECT_FALSE(mainIsGuarded(TU.build())); 508 } 509 510 // Check our handling of files that include themselves. 511 // Ideally we allow this if the file has header guards. 512 // 513 // Note: the semicolons (empty statements) are significant! 514 // - they force the preamble to end and the body to begin. Directives can have 515 // different effects in the preamble vs main file (which we try to hide). 516 // - if the preamble would otherwise cover the whole file, a trailing semicolon 517 // forces their sizes to be different. This is significant because the file 518 // size is part of the lookup key for HeaderFileInfo, and we don't want to 519 // rely on the preamble's HFI being looked up when parsing the main file. 520 TEST(ParsedASTTest, HeaderGuardsSelfInclude) { 521 // Disable include cleaner diagnostics to prevent them from interfering with 522 // other diagnostics. 523 Config Cfg; 524 Cfg.Diagnostics.MissingIncludes = Config::IncludesPolicy::None; 525 Cfg.Diagnostics.UnusedIncludes = Config::IncludesPolicy::None; 526 WithContextValue Ctx(Config::Key, std::move(Cfg)); 527 528 TestTU TU; 529 TU.ImplicitHeaderGuard = false; 530 TU.Filename = "self.h"; 531 532 TU.Code = R"cpp( 533 #include "self.h" // error-ok 534 ; 535 )cpp"; 536 auto AST = TU.build(); 537 EXPECT_THAT(AST.getDiagnostics(), 538 ElementsAre(diag("recursively when building a preamble"))); 539 EXPECT_FALSE(mainIsGuarded(AST)); 540 541 TU.Code = R"cpp( 542 ; 543 #include "self.h" // error-ok 544 )cpp"; 545 AST = TU.build(); 546 EXPECT_THAT(AST.getDiagnostics(), ElementsAre(diag("nested too deeply"))); 547 EXPECT_FALSE(mainIsGuarded(AST)); 548 549 TU.Code = R"cpp( 550 #pragma once 551 #include "self.h" 552 ; 553 )cpp"; 554 AST = TU.build(); 555 EXPECT_THAT(AST.getDiagnostics(), IsEmpty()); 556 EXPECT_TRUE(mainIsGuarded(AST)); 557 558 TU.Code = R"cpp( 559 #pragma once 560 ; 561 #include "self.h" 562 )cpp"; 563 AST = TU.build(); 564 EXPECT_THAT(AST.getDiagnostics(), IsEmpty()); 565 EXPECT_TRUE(mainIsGuarded(AST)); 566 567 TU.Code = R"cpp( 568 ; 569 #pragma once 570 #include "self.h" 571 )cpp"; 572 AST = TU.build(); 573 EXPECT_THAT(AST.getDiagnostics(), IsEmpty()); 574 EXPECT_TRUE(mainIsGuarded(AST)); 575 576 TU.Code = R"cpp( 577 #ifndef GUARD 578 #define GUARD 579 #include "self.h" // error-ok: FIXME, this would be nice to support 580 #endif 581 ; 582 )cpp"; 583 AST = TU.build(); 584 EXPECT_THAT(AST.getDiagnostics(), 585 ElementsAre(diag("recursively when building a preamble"))); 586 EXPECT_TRUE(mainIsGuarded(AST)); 587 588 TU.Code = R"cpp( 589 #ifndef GUARD 590 #define GUARD 591 ; 592 #include "self.h" 593 #endif 594 )cpp"; 595 AST = TU.build(); 596 EXPECT_THAT(AST.getDiagnostics(), IsEmpty()); 597 EXPECT_TRUE(mainIsGuarded(AST)); 598 599 // Guarded too late... 600 TU.Code = R"cpp( 601 #include "self.h" // error-ok 602 #ifndef GUARD 603 #define GUARD 604 ; 605 #endif 606 )cpp"; 607 AST = TU.build(); 608 EXPECT_THAT(AST.getDiagnostics(), 609 ElementsAre(diag("recursively when building a preamble"))); 610 EXPECT_FALSE(mainIsGuarded(AST)); 611 612 TU.Code = R"cpp( 613 #include "self.h" // error-ok 614 ; 615 #ifndef GUARD 616 #define GUARD 617 #endif 618 )cpp"; 619 AST = TU.build(); 620 EXPECT_THAT(AST.getDiagnostics(), 621 ElementsAre(diag("recursively when building a preamble"))); 622 EXPECT_FALSE(mainIsGuarded(AST)); 623 624 TU.Code = R"cpp( 625 ; 626 #ifndef GUARD 627 #define GUARD 628 #include "self.h" 629 #endif 630 )cpp"; 631 AST = TU.build(); 632 EXPECT_THAT(AST.getDiagnostics(), IsEmpty()); 633 EXPECT_FALSE(mainIsGuarded(AST)); 634 635 TU.Code = R"cpp( 636 #include "self.h" // error-ok 637 #pragma once 638 ; 639 )cpp"; 640 AST = TU.build(); 641 EXPECT_THAT(AST.getDiagnostics(), 642 ElementsAre(diag("recursively when building a preamble"))); 643 EXPECT_TRUE(mainIsGuarded(AST)); 644 645 TU.Code = R"cpp( 646 #include "self.h" // error-ok 647 ; 648 #pragma once 649 )cpp"; 650 AST = TU.build(); 651 EXPECT_THAT(AST.getDiagnostics(), 652 ElementsAre(diag("recursively when building a preamble"))); 653 EXPECT_TRUE(mainIsGuarded(AST)); 654 } 655 656 // Tests how we handle common idioms for splitting a header-only library 657 // into interface and implementation files (e.g. *.h vs *.inl). 658 // These files mutually include each other, and need careful handling of include 659 // guards (which interact with preambles). 660 TEST(ParsedASTTest, HeaderGuardsImplIface) { 661 std::string Interface = R"cpp( 662 // error-ok: we assert on diagnostics explicitly 663 template <class T> struct Traits { 664 unsigned size(); 665 }; 666 #include "impl.h" 667 )cpp"; 668 std::string Implementation = R"cpp( 669 // error-ok: we assert on diagnostics explicitly 670 #include "iface.h" 671 template <class T> unsigned Traits<T>::size() { 672 return sizeof(T); 673 } 674 )cpp"; 675 676 TestTU TU; 677 TU.ImplicitHeaderGuard = false; // We're testing include guard handling! 678 TU.ExtraArgs.push_back("-xc++-header"); 679 680 // Editing the interface file, which is include guarded (easy case). 681 // We mostly get this right via PP if we don't recognize the include guard. 682 TU.Filename = "iface.h"; 683 TU.Code = guard(Interface); 684 TU.AdditionalFiles = {{"impl.h", Implementation}}; 685 auto AST = TU.build(); 686 EXPECT_THAT(AST.getDiagnostics(), IsEmpty()); 687 EXPECT_TRUE(mainIsGuarded(AST)); 688 // Slightly harder: the `#pragma once` is part of the preamble, and we 689 // need to transfer it to the main file's HeaderFileInfo. 690 TU.Code = once(Interface); 691 AST = TU.build(); 692 EXPECT_THAT(AST.getDiagnostics(), IsEmpty()); 693 EXPECT_TRUE(mainIsGuarded(AST)); 694 695 // Editing the implementation file, which is not include guarded. 696 TU.Filename = "impl.h"; 697 TU.Code = Implementation; 698 TU.AdditionalFiles = {{"iface.h", guard(Interface)}}; 699 AST = TU.build(); 700 // The diagnostic is unfortunate in this case, but correct per our model. 701 // Ultimately the include is skipped and the code is parsed correctly though. 702 EXPECT_THAT(AST.getDiagnostics(), 703 ElementsAre(diag("in included file: main file cannot be included " 704 "recursively when building a preamble"))); 705 EXPECT_FALSE(mainIsGuarded(AST)); 706 // Interface is pragma once guarded, same thing. 707 TU.AdditionalFiles = {{"iface.h", once(Interface)}}; 708 AST = TU.build(); 709 EXPECT_THAT(AST.getDiagnostics(), 710 ElementsAre(diag("in included file: main file cannot be included " 711 "recursively when building a preamble"))); 712 EXPECT_FALSE(mainIsGuarded(AST)); 713 } 714 715 TEST(ParsedASTTest, DiscoversPragmaMarks) { 716 TestTU TU; 717 TU.AdditionalFiles["Header.h"] = R"( 718 #pragma mark - Something API 719 int something(); 720 #pragma mark Something else 721 )"; 722 TU.Code = R"cpp( 723 #include "Header.h" 724 #pragma mark In Preamble 725 #pragma mark - Something Impl 726 int something() { return 1; } 727 #pragma mark End 728 )cpp"; 729 auto AST = TU.build(); 730 731 EXPECT_THAT(AST.getMarks(), ElementsAre(pragmaTrivia(" In Preamble"), 732 pragmaTrivia(" - Something Impl"), 733 pragmaTrivia(" End"))); 734 } 735 736 TEST(ParsedASTTest, GracefulFailureOnAssemblyFile) { 737 std::string Filename = "TestTU.S"; 738 std::string Code = R"S( 739 main: 740 # test comment 741 bx lr 742 )S"; 743 744 // The rest is a simplified version of TestTU::build(). 745 // Don't call TestTU::build() itself because it would assert on 746 // failure to build an AST. 747 MockFS FS; 748 std::string FullFilename = testPath(Filename); 749 FS.Files[FullFilename] = Code; 750 ParseInputs Inputs; 751 auto &Argv = Inputs.CompileCommand.CommandLine; 752 Argv = {"clang"}; 753 Argv.push_back(FullFilename); 754 Inputs.CompileCommand.Filename = FullFilename; 755 Inputs.CompileCommand.Directory = testRoot(); 756 Inputs.Contents = Code; 757 Inputs.TFS = &FS; 758 StoreDiags Diags; 759 auto CI = buildCompilerInvocation(Inputs, Diags); 760 assert(CI && "Failed to build compilation invocation."); 761 auto AST = ParsedAST::build(FullFilename, Inputs, std::move(CI), {}, nullptr); 762 763 EXPECT_FALSE(AST.has_value()) 764 << "Should not try to build AST for assembly source file"; 765 } 766 767 TEST(ParsedASTTest, PreambleWithDifferentTarget) { 768 constexpr std::string_view kPreambleTarget = "x86_64"; 769 // Specifically picking __builtin_va_list as it triggers crashes when 770 // switching to wasm. 771 // It's due to different predefined types in different targets. 772 auto TU = TestTU::withHeaderCode("void foo(__builtin_va_list);"); 773 TU.Code = "void bar() { foo(2); }"; 774 TU.ExtraArgs.emplace_back("-target"); 775 TU.ExtraArgs.emplace_back(kPreambleTarget); 776 const auto Preamble = TU.preamble(); 777 778 // Switch target to wasm. 779 TU.ExtraArgs.pop_back(); 780 TU.ExtraArgs.emplace_back("wasm32"); 781 782 IgnoreDiagnostics Diags; 783 MockFS FS; 784 auto Inputs = TU.inputs(FS); 785 auto CI = buildCompilerInvocation(Inputs, Diags); 786 ASSERT_TRUE(CI) << "Failed to build compiler invocation"; 787 788 auto AST = ParsedAST::build(testPath(TU.Filename), std::move(Inputs), 789 std::move(CI), {}, Preamble); 790 791 ASSERT_TRUE(AST); 792 // We use the target from preamble, not with the most-recent flags. 793 EXPECT_EQ(AST->getASTContext().getTargetInfo().getTriple().getArchName(), 794 llvm::StringRef(kPreambleTarget)); 795 } 796 } // namespace 797 } // namespace clangd 798 } // namespace clang 799