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