xref: /llvm-project/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp (revision b1aea98cfa357e23f4bb52232da5f41781f23bff)
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