[MLIR][NVVM] Add Op for TMA Store with reduction (#118853)
[llvm-project.git] / clang-tools-extra / clangd / unittests / ParsedASTTests.cpp
blob6ee641caeefe3d94741472793305164ee9927628
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/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>
44 namespace clang {
45 namespace clangd {
46 namespace {
48 using ::testing::AllOf;
49 using ::testing::Contains;
50 using ::testing::ElementsAre;
51 using ::testing::ElementsAreArray;
52 using ::testing::IsEmpty;
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);
62 return false;
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);
73 return false;
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);
91 if (Args->size() == 0)
92 return ArgName == SpecializationArgs;
93 return ArgName == "<" + SpecializationArgs + ">";
96 if (const NamedDecl *ND = dyn_cast<NamedDecl>(arg))
97 return printTemplateSpecializationArgs(*ND) == ArgName;
98 return false;
101 MATCHER_P(pragmaTrivia, P, "") { return arg.Trivia == P; }
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);
110 TEST(ParsedASTTest, TopLevelDecls) {
111 TestTU TU;
112 TU.HeaderCode = R"(
113 int header1();
114 int header2;
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"))}));
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() {}
136 )cpp";
137 TU.Code = R"cpp(
138 int main() {
139 H<int> h;
140 h.foo();
142 )cpp";
143 auto AST = TU.build();
144 EXPECT_THAT(AST.getLocalTopLevelDecls(), ElementsAre(declNamed("main")));
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);
155 )cpp";
157 auto AST = TU.build();
158 EXPECT_THAT(AST.getLocalTopLevelDecls(),
159 ElementsAre(declNamed("f"), declNamed("s")));
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);
172 template <class T>
173 struct V {};
174 template<class T>
175 struct V<T*> {};
176 template <>
177 struct V<bool> {};
179 template<class T>
180 T foo = T(10);
181 int i = foo<int>;
182 double d = foo<double>;
184 template <class T>
185 int foo<T*> = 0;
186 template <>
187 int foo<bool> = 0;
188 )cpp";
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>"))}));
206 TEST(ParsedASTTest, IgnoresDelayedTemplateParsing) {
207 auto TU = TestTU::withCode(R"cpp(
208 template <typename T> void xxx() {
209 int yyy = 0;
211 )cpp");
212 TU.ExtraArgs.push_back("-fdelayed-template-parsing");
213 auto AST = TU.build();
214 EXPECT_EQ(Decl::Var, findUnqualifiedDecl(AST, "yyy").getKind());
217 TEST(ParsedASTTest, TokensAfterPreamble) {
218 TestTU TU;
219 TU.AdditionalFiles["foo.h"] = R"(
220 int foo();
222 TU.Code = R"cpp(
223 #include "foo.h"
224 first_token;
225 void test() {
226 // error-ok: invalid syntax, just examining token stream
228 last_token
229 )cpp";
230 auto AST = TU.build();
231 const syntax::TokenBuffer &T = AST.getTokens();
232 const auto &SM = AST.getSourceManager();
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");
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");
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() {}";
256 auto AST = TU.build();
257 const syntax::TokenBuffer &T = AST.getTokens();
258 const auto &SM = AST.getSourceManager();
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), "}");
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);
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);
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));
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;
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);
307 // Macros included not from preamble not included.
308 #include "foo.inc"
310 int printf(const char*, ...);
311 void exit(int);
312 #define ^assert(COND) if (!(COND)) { printf("%s", #COND); exit(0); }
314 void test() {
315 // Includes macro expansions in arguments that are expressions
316 ^assert(0 <= ^BAR);
319 #ifdef ^UNDEFINED
320 #endif
322 #define ^MULTIPLE_DEFINITION 1
323 #undef ^MULTIPLE_DEFINITION
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);
345 for (const auto &R : AST.getMacros().UnknownMacros)
346 MacroExpansionPositions.push_back(R.StartOffset);
347 EXPECT_THAT(MacroExpansionPositions,
348 testing::UnorderedElementsAreArray(TestCase.points()));
351 MATCHER_P(withFileName, Inc, "") { return arg.FileName == Inc; }
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();
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());
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);
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));
409 TEST(ParsedASTTest, PatchesDeletedIncludes) {
410 TestTU TU;
411 TU.Filename = "foo.cpp";
412 TU.Code = "";
413 auto ExpectedAST = TU.build();
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>")));
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);
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]);
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);
464 std::string once(llvm::StringRef Code) {
465 return llvm::formatv("#pragma once\n{0}\n", Code);
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);
476 MATCHER_P(diag, Desc, "") {
477 return llvm::StringRef(arg.Message).contains(Desc);
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;
485 TU.Code = ";";
486 EXPECT_FALSE(mainIsGuarded(TU.build()));
488 TU.Code = guard(";");
489 EXPECT_TRUE(mainIsGuarded(TU.build()));
491 TU.Code = once(";");
492 EXPECT_TRUE(mainIsGuarded(TU.build()));
494 TU.Code = R"cpp(
496 #pragma once
497 )cpp";
498 EXPECT_FALSE(mainIsGuarded(TU.build())); // FIXME: true
500 TU.Code = R"cpp(
502 #ifndef GUARD
503 #define GUARD
505 #endif
506 )cpp";
507 EXPECT_FALSE(mainIsGuarded(TU.build()));
510 // Check our handling of files that include themselves.
511 // Ideally we allow this if the file has header guards.
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));
528 TestTU TU;
529 TU.ImplicitHeaderGuard = false;
530 TU.Filename = "self.h";
532 TU.Code = R"cpp(
533 #include "self.h" // error-ok
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));
541 TU.Code = R"cpp(
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));
549 TU.Code = R"cpp(
550 #pragma once
551 #include "self.h"
553 )cpp";
554 AST = TU.build();
555 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
556 EXPECT_TRUE(mainIsGuarded(AST));
558 TU.Code = R"cpp(
559 #pragma once
561 #include "self.h"
562 )cpp";
563 AST = TU.build();
564 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
565 EXPECT_TRUE(mainIsGuarded(AST));
567 TU.Code = R"cpp(
569 #pragma once
570 #include "self.h"
571 )cpp";
572 AST = TU.build();
573 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
574 EXPECT_TRUE(mainIsGuarded(AST));
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
582 )cpp";
583 AST = TU.build();
584 EXPECT_THAT(AST.getDiagnostics(),
585 ElementsAre(diag("recursively when building a preamble")));
586 EXPECT_TRUE(mainIsGuarded(AST));
588 TU.Code = R"cpp(
589 #ifndef GUARD
590 #define GUARD
592 #include "self.h"
593 #endif
594 )cpp";
595 AST = TU.build();
596 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
597 EXPECT_TRUE(mainIsGuarded(AST));
599 // Guarded too late...
600 TU.Code = R"cpp(
601 #include "self.h" // error-ok
602 #ifndef GUARD
603 #define GUARD
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));
612 TU.Code = R"cpp(
613 #include "self.h" // error-ok
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));
624 TU.Code = R"cpp(
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));
635 TU.Code = R"cpp(
636 #include "self.h" // error-ok
637 #pragma once
639 )cpp";
640 AST = TU.build();
641 EXPECT_THAT(AST.getDiagnostics(),
642 ElementsAre(diag("recursively when building a preamble")));
643 EXPECT_TRUE(mainIsGuarded(AST));
645 TU.Code = R"cpp(
646 #include "self.h" // error-ok
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));
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();
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);
674 )cpp";
676 TestTU TU;
677 TU.ImplicitHeaderGuard = false; // We're testing include guard handling!
678 TU.ExtraArgs.push_back("-xc++-header");
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));
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));
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
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();
731 EXPECT_THAT(AST.getMarks(), ElementsAre(pragmaTrivia(" In Preamble"),
732 pragmaTrivia(" - Something Impl"),
733 pragmaTrivia(" End")));
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";
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);
763 EXPECT_FALSE(AST.has_value())
764 << "Should not try to build AST for assembly source file";
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();
778 // Switch target to wasm.
779 TU.ExtraArgs.pop_back();
780 TU.ExtraArgs.emplace_back("wasm32");
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";
788 auto AST = ParsedAST::build(testPath(TU.Filename), std::move(Inputs),
789 std::move(CI), {}, Preamble);
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));
796 } // namespace
797 } // namespace clangd
798 } // namespace clang