clang-tools  11.0.0
ParsedASTTests.cpp
Go to the documentation of this file.
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 "../../clang-tidy/ClangTidyModule.h"
16 #include "../../clang-tidy/ClangTidyModuleRegistry.h"
17 #include "AST.h"
18 #include "Annotations.h"
19 #include "Compiler.h"
20 #include "Diagnostics.h"
21 #include "Headers.h"
22 #include "ParsedAST.h"
23 #include "Preamble.h"
24 #include "SourceCode.h"
25 #include "TestFS.h"
26 #include "TestTU.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/Lex/PPCallbacks.h"
32 #include "clang/Lex/Token.h"
33 #include "clang/Tooling/Syntax/Tokens.h"
34 #include "llvm/ADT/STLExtras.h"
35 #include "llvm/ADT/StringRef.h"
36 #include "llvm/Support/ScopedPrinter.h"
37 #include "gmock/gmock-matchers.h"
38 #include "gmock/gmock.h"
39 #include "gtest/gtest.h"
40 
41 namespace clang {
42 namespace clangd {
43 namespace {
44 
45 using ::testing::AllOf;
46 using ::testing::ElementsAre;
47 using ::testing::ElementsAreArray;
48 
49 MATCHER_P(DeclNamed, Name, "") {
50  if (NamedDecl *ND = dyn_cast<NamedDecl>(arg))
51  if (ND->getName() == Name)
52  return true;
53  if (auto *Stream = result_listener->stream()) {
54  llvm::raw_os_ostream OS(*Stream);
55  arg->dump(OS);
56  }
57  return false;
58 }
59 
60 // Matches if the Decl has template args equal to ArgName. If the decl is a
61 // NamedDecl and ArgName is an empty string it also matches.
62 MATCHER_P(WithTemplateArgs, ArgName, "") {
63  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(arg)) {
64  if (const auto *Args = FD->getTemplateSpecializationArgs()) {
65  std::string SpecializationArgs;
66  // Without the PrintingPolicy "bool" will be printed as "_Bool".
67  LangOptions LO;
68  PrintingPolicy Policy(LO);
69  Policy.adjustForCPlusPlus();
70  for (const auto &Arg : Args->asArray()) {
71  if (SpecializationArgs.size() > 0)
72  SpecializationArgs += ",";
73  SpecializationArgs += Arg.getAsType().getAsString(Policy);
74  }
75  if (Args->size() == 0)
76  return ArgName == SpecializationArgs;
77  return ArgName == "<" + SpecializationArgs + ">";
78  }
79  }
80  if (const NamedDecl *ND = dyn_cast<NamedDecl>(arg))
81  return printTemplateSpecializationArgs(*ND) == ArgName;
82  return false;
83 }
84 
85 MATCHER_P(RangeIs, R, "") {
86  return arg.beginOffset() == R.Begin && arg.endOffset() == R.End;
87 }
88 
89 MATCHER(EqInc, "") {
90  Inclusion Actual = testing::get<0>(arg);
91  Inclusion Expected = testing::get<1>(arg);
92  return std::tie(Actual.HashLine, Actual.Written) ==
93  std::tie(Expected.HashLine, Expected.Written);
94 }
95 
96 TEST(ParsedASTTest, TopLevelDecls) {
97  TestTU TU;
98  TU.HeaderCode = R"(
99  int header1();
100  int header2;
101  )";
102  TU.Code = "int main();";
103  auto AST = TU.build();
104  EXPECT_THAT(AST.getLocalTopLevelDecls(), ElementsAre(DeclNamed("main")));
105 }
106 
107 TEST(ParsedASTTest, DoesNotGetIncludedTopDecls) {
108  TestTU TU;
109  TU.HeaderCode = R"cpp(
110  #define LL void foo(){}
111  template<class T>
112  struct H {
113  H() {}
114  LL
115  };
116  )cpp";
117  TU.Code = R"cpp(
118  int main() {
119  H<int> h;
120  h.foo();
121  }
122  )cpp";
123  auto AST = TU.build();
124  EXPECT_THAT(AST.getLocalTopLevelDecls(), ElementsAre(DeclNamed("main")));
125 }
126 
127 TEST(ParsedASTTest, DoesNotGetImplicitTemplateTopDecls) {
128  TestTU TU;
129  TU.Code = R"cpp(
130  template<typename T>
131  void f(T) {}
132  void s() {
133  f(10UL);
134  }
135  )cpp";
136 
137  auto AST = TU.build();
138  EXPECT_THAT(AST.getLocalTopLevelDecls(),
139  ElementsAre(DeclNamed("f"), DeclNamed("s")));
140 }
141 
142 TEST(ParsedASTTest,
143  GetsExplicitInstantiationAndSpecializationTemplateTopDecls) {
144  TestTU TU;
145  TU.Code = R"cpp(
146  template <typename T>
147  void f(T) {}
148  template<>
149  void f(bool);
150  template void f(double);
151 
152  template <class T>
153  struct V {};
154  template<class T>
155  struct V<T*> {};
156  template <>
157  struct V<bool> {};
158 
159  template<class T>
160  T foo = T(10);
161  int i = foo<int>;
162  double d = foo<double>;
163 
164  template <class T>
165  int foo<T*> = 0;
166  template <>
167  int foo<bool> = 0;
168  )cpp";
169  // FIXME: Auto-completion in a template requires disabling delayed template
170  // parsing.
171  TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
172 
173  auto AST = TU.build();
174  EXPECT_THAT(
175  AST.getLocalTopLevelDecls(),
176  ElementsAreArray({AllOf(DeclNamed("f"), WithTemplateArgs("")),
177  AllOf(DeclNamed("f"), WithTemplateArgs("<bool>")),
178  AllOf(DeclNamed("f"), WithTemplateArgs("<double>")),
179  AllOf(DeclNamed("V"), WithTemplateArgs("")),
180  AllOf(DeclNamed("V"), WithTemplateArgs("<T *>")),
181  AllOf(DeclNamed("V"), WithTemplateArgs("<bool>")),
182  AllOf(DeclNamed("foo"), WithTemplateArgs("")),
183  AllOf(DeclNamed("i"), WithTemplateArgs("")),
184  AllOf(DeclNamed("d"), WithTemplateArgs("")),
185  AllOf(DeclNamed("foo"), WithTemplateArgs("<T *>")),
186  AllOf(DeclNamed("foo"), WithTemplateArgs("<bool>"))}));
187 }
188 
189 TEST(ParsedASTTest, IgnoresDelayedTemplateParsing) {
190  auto TU = TestTU::withCode(R"cpp(
191  template <typename T> void xxx() {
192  int yyy = 0;
193  }
194  )cpp");
195  TU.ExtraArgs.push_back("-fdelayed-template-parsing");
196  auto AST = TU.build();
197  EXPECT_EQ(Decl::Var, findUnqualifiedDecl(AST, "yyy").getKind());
198 }
199 
200 TEST(ParsedASTTest, TokensAfterPreamble) {
201  TestTU TU;
202  TU.AdditionalFiles["foo.h"] = R"(
203  int foo();
204  )";
205  TU.Code = R"cpp(
206  #include "foo.h"
207  first_token;
208  void test() {
209  // error-ok: invalid syntax, just examining token stream
210  }
211  last_token
212 )cpp";
213  auto AST = TU.build();
214  const syntax::TokenBuffer &T = AST.getTokens();
215  const auto &SM = AST.getSourceManager();
216 
217  ASSERT_GT(T.expandedTokens().size(), 2u);
218  // Check first token after the preamble.
219  EXPECT_EQ(T.expandedTokens().front().text(SM), "first_token");
220  // Last token is always 'eof'.
221  EXPECT_EQ(T.expandedTokens().back().kind(), tok::eof);
222  // Check the token before 'eof'.
223  EXPECT_EQ(T.expandedTokens().drop_back().back().text(SM), "last_token");
224 
225  // The spelled tokens for the main file should have everything.
226  auto Spelled = T.spelledTokens(SM.getMainFileID());
227  ASSERT_FALSE(Spelled.empty());
228  EXPECT_EQ(Spelled.front().kind(), tok::hash);
229  EXPECT_EQ(Spelled.back().text(SM), "last_token");
230 }
231 
232 TEST(ParsedASTTest, NoCrashOnTokensWithTidyCheck) {
233  TestTU TU;
234  // this check runs the preprocessor, we need to make sure it does not break
235  // our recording logic.
236  TU.ClangTidyChecks = "modernize-use-trailing-return-type";
237  TU.Code = "inline int foo() {}";
238 
239  auto AST = TU.build();
240  const syntax::TokenBuffer &T = AST.getTokens();
241  const auto &SM = AST.getSourceManager();
242 
243  ASSERT_GT(T.expandedTokens().size(), 7u);
244  // Check first token after the preamble.
245  EXPECT_EQ(T.expandedTokens().front().text(SM), "inline");
246  // Last token is always 'eof'.
247  EXPECT_EQ(T.expandedTokens().back().kind(), tok::eof);
248  // Check the token before 'eof'.
249  EXPECT_EQ(T.expandedTokens().drop_back().back().text(SM), "}");
250 }
251 
252 TEST(ParsedASTTest, CanBuildInvocationWithUnknownArgs) {
253  MockFS FS;
254  FS.Files = {{testPath("foo.cpp"), "void test() {}"}};
255  // Unknown flags should not prevent a build of compiler invocation.
256  ParseInputs Inputs;
257  Inputs.TFS = &FS;
258  Inputs.CompileCommand.CommandLine = {"clang", "-fsome-unknown-flag",
259  testPath("foo.cpp")};
260  IgnoreDiagnostics IgnoreDiags;
261  EXPECT_NE(buildCompilerInvocation(Inputs, IgnoreDiags), nullptr);
262 
263  // Unknown forwarded to -cc1 should not a failure either.
264  Inputs.CompileCommand.CommandLine = {
265  "clang", "-Xclang", "-fsome-unknown-flag", testPath("foo.cpp")};
266  EXPECT_NE(buildCompilerInvocation(Inputs, IgnoreDiags), nullptr);
267 }
268 
269 TEST(ParsedASTTest, CollectsMainFileMacroExpansions) {
270  Annotations TestCase(R"cpp(
271  #define ^MACRO_ARGS(X, Y) X Y
272  // - preamble ends
273  ^ID(int A);
274  // Macro arguments included.
275  ^MACRO_ARGS(^MACRO_ARGS(^MACRO_EXP(int), E), ^ID(= 2));
276 
277  // Macro names inside other macros not included.
278  #define ^MACRO_ARGS2(X, Y) X Y
279  #define ^FOO BAR
280  #define ^BAR 1
281  int F = ^FOO;
282 
283  // Macros from token concatenations not included.
284  #define ^CONCAT(X) X##A()
285  #define ^PREPEND(X) MACRO##X()
286  #define ^MACROA() 123
287  int G = ^CONCAT(MACRO);
288  int H = ^PREPEND(A);
289 
290  // Macros included not from preamble not included.
291  #include "foo.inc"
292 
293  int printf(const char*, ...);
294  void exit(int);
295  #define ^assert(COND) if (!(COND)) { printf("%s", #COND); exit(0); }
296 
297  void test() {
298  // Includes macro expansions in arguments that are expressions
299  ^assert(0 <= ^BAR);
300  }
301 
302  #ifdef ^UNDEFINED
303  #endif
304 
305  #define ^MULTIPLE_DEFINITION 1
306  #undef ^MULTIPLE_DEFINITION
307 
308  #define ^MULTIPLE_DEFINITION 2
309  #undef ^MULTIPLE_DEFINITION
310  )cpp");
311  auto TU = TestTU::withCode(TestCase.code());
312  TU.HeaderCode = R"cpp(
313  #define ID(X) X
314  #define MACRO_EXP(X) ID(X)
315  MACRO_EXP(int B);
316  )cpp";
317  TU.AdditionalFiles["foo.inc"] = R"cpp(
318  int C = ID(1);
319  #define DEF 1
320  int D = DEF;
321  )cpp";
322  ParsedAST AST = TU.build();
323  std::vector<Position> MacroExpansionPositions;
324  for (const auto &SIDToRefs : AST.getMacros().MacroRefs) {
325  for (const auto &R : SIDToRefs.second)
326  MacroExpansionPositions.push_back(R.start);
327  }
328  for (const auto &R : AST.getMacros().UnknownMacros)
329  MacroExpansionPositions.push_back(R.start);
330  EXPECT_THAT(MacroExpansionPositions,
331  testing::UnorderedElementsAreArray(TestCase.points()));
332 }
333 
334 MATCHER_P(WithFileName, Inc, "") { return arg.FileName == Inc; }
335 
336 TEST(ParsedASTTest, ReplayPreambleForTidyCheckers) {
337  struct Inclusion {
338  Inclusion(const SourceManager &SM, SourceLocation HashLoc,
339  const Token &IncludeTok, llvm::StringRef FileName, bool IsAngled,
340  CharSourceRange FilenameRange)
341  : HashOffset(SM.getDecomposedLoc(HashLoc).second), IncTok(IncludeTok),
342  IncDirective(IncludeTok.getIdentifierInfo()->getName()),
343  FileNameOffset(SM.getDecomposedLoc(FilenameRange.getBegin()).second),
345  size_t HashOffset;
346  syntax::Token IncTok;
347  llvm::StringRef IncDirective;
348  size_t FileNameOffset;
349  llvm::StringRef FileName;
350  bool IsAngled;
351  };
352  static std::vector<Inclusion> Includes;
353  static std::vector<syntax::Token> SkippedFiles;
354  struct ReplayPreamblePPCallback : public PPCallbacks {
355  const SourceManager &SM;
356  explicit ReplayPreamblePPCallback(const SourceManager &SM) : SM(SM) {}
357 
358  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
359  StringRef FileName, bool IsAngled,
360  CharSourceRange FilenameRange, const FileEntry *,
361  StringRef, StringRef, const Module *,
362  SrcMgr::CharacteristicKind) override {
363  Includes.emplace_back(SM, HashLoc, IncludeTok, FileName, IsAngled,
364  FilenameRange);
365  }
366 
367  void FileSkipped(const FileEntryRef &, const Token &FilenameTok,
368  SrcMgr::CharacteristicKind) override {
369  SkippedFiles.emplace_back(FilenameTok);
370  }
371  };
372  struct ReplayPreambleCheck : public tidy::ClangTidyCheck {
373  ReplayPreambleCheck(StringRef Name, tidy::ClangTidyContext *Context)
374  : ClangTidyCheck(Name, Context) {}
375  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
376  Preprocessor *ModuleExpanderPP) override {
377  PP->addPPCallbacks(::std::make_unique<ReplayPreamblePPCallback>(SM));
378  }
379  };
380  struct ReplayPreambleModule : public tidy::ClangTidyModule {
381  void
382  addCheckFactories(tidy::ClangTidyCheckFactories &CheckFactories) override {
383  CheckFactories.registerCheck<ReplayPreambleCheck>(
384  "replay-preamble-check");
385  }
386  };
387 
388  static tidy::ClangTidyModuleRegistry::Add<ReplayPreambleModule> X(
389  "replay-preamble-module", "");
390  TestTU TU;
391  // This check records inclusion directives replayed by clangd.
392  TU.ClangTidyChecks = "replay-preamble-check";
393  llvm::Annotations Test(R"cpp(
394  $hash^#$include[[import]] $filebegin^"$filerange[[bar.h]]"
395  $hash^#$include[[include_next]] $filebegin^"$filerange[[baz.h]]"
396  $hash^#$include[[include]] $filebegin^<$filerange[[a.h]]>)cpp");
397  llvm::StringRef Code = Test.code();
398  TU.Code = Code.str();
399  TU.AdditionalFiles["bar.h"] = "";
400  TU.AdditionalFiles["baz.h"] = "";
401  TU.AdditionalFiles["a.h"] = "";
402  // Since we are also testing #import directives, and they don't make much
403  // sense in c++ (also they actually break on windows), just set language to
404  // obj-c.
405  TU.ExtraArgs = {"-isystem.", "-xobjective-c"};
406 
407  const auto &AST = TU.build();
408  const auto &SM = AST.getSourceManager();
409 
410  auto HashLocs = Test.points("hash");
411  ASSERT_EQ(HashLocs.size(), Includes.size());
412  auto IncludeRanges = Test.ranges("include");
413  ASSERT_EQ(IncludeRanges.size(), Includes.size());
414  auto FileBeginLocs = Test.points("filebegin");
415  ASSERT_EQ(FileBeginLocs.size(), Includes.size());
416  auto FileRanges = Test.ranges("filerange");
417  ASSERT_EQ(FileRanges.size(), Includes.size());
418 
419  ASSERT_EQ(SkippedFiles.size(), Includes.size());
420  for (size_t I = 0; I < Includes.size(); ++I) {
421  const auto &Inc = Includes[I];
422 
423  EXPECT_EQ(Inc.HashOffset, HashLocs[I]);
424 
425  auto IncRange = IncludeRanges[I];
426  EXPECT_THAT(Inc.IncTok.range(SM), RangeIs(IncRange));
427  EXPECT_EQ(Inc.IncTok.kind(), tok::identifier);
428  EXPECT_EQ(Inc.IncDirective,
429  Code.substr(IncRange.Begin, IncRange.End - IncRange.Begin));
430 
431  EXPECT_EQ(Inc.FileNameOffset, FileBeginLocs[I]);
432  EXPECT_EQ(Inc.IsAngled, Code[FileBeginLocs[I]] == '<');
433 
434  auto FileRange = FileRanges[I];
435  EXPECT_EQ(Inc.FileName,
436  Code.substr(FileRange.Begin, FileRange.End - FileRange.Begin));
437 
438  EXPECT_EQ(SM.getDecomposedLoc(SkippedFiles[I].location()).second,
439  Inc.FileNameOffset);
440  // This also contains quotes/angles so increment the range by one from both
441  // sides.
442  EXPECT_EQ(
443  SkippedFiles[I].text(SM),
444  Code.substr(FileRange.Begin - 1, FileRange.End - FileRange.Begin + 2));
445  EXPECT_EQ(SkippedFiles[I].kind(), tok::header_name);
446  }
447 
448  TU.AdditionalFiles["a.h"] = "";
449  TU.AdditionalFiles["b.h"] = "";
450  TU.AdditionalFiles["c.h"] = "";
451  // Make sure replay logic works with patched preambles.
452  llvm::StringLiteral Baseline = R"cpp(
453  #include "a.h"
454  #include "c.h")cpp";
455  MockFS FS;
456  TU.Code = Baseline.str();
457  auto Inputs = TU.inputs(FS);
458  auto BaselinePreamble = TU.preamble();
459  ASSERT_TRUE(BaselinePreamble);
460 
461  // First make sure we don't crash on various modifications to the preamble.
462  llvm::StringLiteral Cases[] = {
463  // clang-format off
464  // New include in middle.
465  R"cpp(
466  #include "a.h"
467  #include "b.h"
468  #include "c.h")cpp",
469  // New include at top.
470  R"cpp(
471  #include "b.h"
472  #include "a.h"
473  #include "c.h")cpp",
474  // New include at bottom.
475  R"cpp(
476  #include "a.h"
477  #include "c.h"
478  #include "b.h")cpp",
479  // Same size with a missing include.
480  R"cpp(
481  #include "a.h"
482  #include "b.h")cpp",
483  // Smaller with no new includes.
484  R"cpp(
485  #include "a.h")cpp",
486  // Smaller with a new includes.
487  R"cpp(
488  #include "b.h")cpp",
489  // clang-format on
490  };
491  for (llvm::StringLiteral Case : Cases) {
492  TU.Code = Case.str();
493 
494  IgnoreDiagnostics Diags;
495  auto CI = buildCompilerInvocation(TU.inputs(FS), Diags);
496  auto PatchedAST = ParsedAST::build(testPath(TU.Filename), TU.inputs(FS),
497  std::move(CI), {}, BaselinePreamble);
498  ASSERT_TRUE(PatchedAST);
499  EXPECT_TRUE(PatchedAST->getDiagnostics().empty());
500  }
501 
502  // Then ensure correctness by making sure includes were seen only once.
503  // Note that we first see the includes from the patch, as preamble includes
504  // are replayed after exiting the built-in file.
505  Includes.clear();
506  TU.Code = R"cpp(
507  #include "a.h"
508  #include "b.h")cpp";
509  IgnoreDiagnostics Diags;
510  auto CI = buildCompilerInvocation(TU.inputs(FS), Diags);
511  auto PatchedAST = ParsedAST::build(testPath(TU.Filename), TU.inputs(FS),
512  std::move(CI), {}, BaselinePreamble);
513  ASSERT_TRUE(PatchedAST);
514  EXPECT_TRUE(PatchedAST->getDiagnostics().empty());
515  EXPECT_THAT(Includes,
516  ElementsAre(WithFileName(testPath("__preamble_patch__.h")),
517  WithFileName("b.h"), WithFileName("a.h")));
518 }
519 
520 TEST(ParsedASTTest, PatchesAdditionalIncludes) {
521  llvm::StringLiteral ModifiedContents = R"cpp(
522  #include "baz.h"
523  #include "foo.h"
524  #include "sub/aux.h"
525  void bar() {
526  foo();
527  baz();
528  aux();
529  })cpp";
530  // Build expected ast with symbols coming from headers.
531  TestTU TU;
532  TU.Filename = "foo.cpp";
533  TU.AdditionalFiles["foo.h"] = "void foo();";
534  TU.AdditionalFiles["sub/baz.h"] = "void baz();";
535  TU.AdditionalFiles["sub/aux.h"] = "void aux();";
536  TU.ExtraArgs = {"-I" + testPath("sub")};
537  TU.Code = ModifiedContents.str();
538  auto ExpectedAST = TU.build();
539 
540  // Build preamble with no includes.
541  TU.Code = "";
542  StoreDiags Diags;
543  MockFS FS;
544  auto Inputs = TU.inputs(FS);
546  auto EmptyPreamble =
547  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
548  ASSERT_TRUE(EmptyPreamble);
549  EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, testing::IsEmpty());
550 
551  // Now build an AST using empty preamble and ensure patched includes worked.
552  TU.Code = ModifiedContents.str();
553  Inputs = TU.inputs(FS);
554  auto PatchedAST = ParsedAST::build(testPath("foo.cpp"), Inputs, std::move(CI),
555  {}, EmptyPreamble);
556  ASSERT_TRUE(PatchedAST);
557  ASSERT_TRUE(PatchedAST->getDiagnostics().empty());
558 
559  // Ensure source location information is correct, including resolved paths.
560  EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
561  testing::Pointwise(
562  EqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes));
563  auto StringMapToVector = [](const llvm::StringMap<unsigned> SM) {
564  std::vector<std::pair<std::string, unsigned>> Res;
565  for (const auto &E : SM)
566  Res.push_back({E.first().str(), E.second});
567  llvm::sort(Res);
568  return Res;
569  };
570  // Ensure file proximity signals are correct.
571  EXPECT_EQ(StringMapToVector(PatchedAST->getIncludeStructure().includeDepth(
572  testPath("foo.cpp"))),
573  StringMapToVector(ExpectedAST.getIncludeStructure().includeDepth(
574  testPath("foo.cpp"))));
575 }
576 
577 TEST(ParsedASTTest, PatchesDeletedIncludes) {
578  TestTU TU;
579  TU.Filename = "foo.cpp";
580  TU.Code = "";
581  auto ExpectedAST = TU.build();
582 
583  // Build preamble with no includes.
584  TU.Code = R"cpp(#include <foo.h>)cpp";
585  StoreDiags Diags;
586  MockFS FS;
587  auto Inputs = TU.inputs(FS);
589  auto BaselinePreamble =
590  buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr);
591  ASSERT_TRUE(BaselinePreamble);
592  EXPECT_THAT(BaselinePreamble->Includes.MainFileIncludes,
593  ElementsAre(testing::Field(&Inclusion::Written, "<foo.h>")));
594 
595  // Now build an AST using additional includes and check that locations are
596  // correctly parsed.
597  TU.Code = "";
598  Inputs = TU.inputs(FS);
599  auto PatchedAST = ParsedAST::build(testPath("foo.cpp"), Inputs, std::move(CI),
600  {}, BaselinePreamble);
601  ASSERT_TRUE(PatchedAST);
602 
603  // Ensure source location information is correct.
604  EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
605  testing::Pointwise(
606  EqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes));
607  auto StringMapToVector = [](const llvm::StringMap<unsigned> SM) {
608  std::vector<std::pair<std::string, unsigned>> Res;
609  for (const auto &E : SM)
610  Res.push_back({E.first().str(), E.second});
611  llvm::sort(Res);
612  return Res;
613  };
614  // Ensure file proximity signals are correct.
615  EXPECT_EQ(StringMapToVector(PatchedAST->getIncludeStructure().includeDepth(
616  testPath("foo.cpp"))),
617  StringMapToVector(ExpectedAST.getIncludeStructure().includeDepth(
618  testPath("foo.cpp"))));
619 }
620 
621 } // namespace
622 } // namespace clangd
623 } // namespace clang
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:704
Headers.h
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::clangd::testPath
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:82
Expected
std::vector< const char * > Expected
Definition: PrintASTTests.cpp:27
clang::clangd::CompletionItemKind::Field
CI
std::unique_ptr< CompilerInvocation > CI
Definition: TUScheduler.cpp:320
TestTU.h
clang::clangd::X
static URISchemeRegistry::Add< TestScheme > X(TestScheme::Scheme, "Test schema")
Preamble.h
clang::clangd::MainFileMacros::MacroRefs
llvm::DenseMap< SymbolID, std::vector< Range > > MacroRefs
Definition: CollectMacros.h:28
clang::clangd::ParseInputs::CompileCommand
tooling::CompileCommand CompileCommand
Definition: Compiler.h:48
clang::clangd::findUnqualifiedDecl
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
Definition: TestTU.cpp:206
clang::clangd::ParsedAST::build
static llvm::Optional< ParsedAST > build(llvm::StringRef Filename, const ParseInputs &Inputs, std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble)
Attempts to run Clang and store the parsed AST.
Definition: ParsedAST.cpp:246
Inputs
ParseInputs Inputs
Definition: TUScheduler.cpp:321
Code
std::string Code
Definition: FindTargetTests.cpp:67
clang::clangd::ParseInputs::TFS
const ThreadsafeFS * TFS
Definition: Compiler.h:49
clang::clangd::buildPreamble
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation CI, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Build a preamble for the new inputs unless an old one can be reused.
Definition: Preamble.cpp:321
clang::clangd::Inclusion::Written
std::string Written
Definition: Headers.h:56
FS
MockFS FS
Definition: ClangdLSPServerTests.cpp:66
TestFS.h
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::clangd::printTemplateSpecializationArgs
std::string printTemplateSpecializationArgs(const NamedDecl &ND)
Prints template arguments of a decl as written in the source code, including enclosing '<' and '>',...
Definition: AST.cpp:248
Diagnostics.h
clang::clangd::TestTU::withCode
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:35
Annotations.h
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:29
clang::clangd::buildCompilerInvocation
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
Definition: Compiler.cpp:45
SourceCode.h
IsAngled
bool IsAngled
true if this was an include with angle brackets
Definition: IncludeOrderCheck.cpp:40
Compiler.h
clang::clangd::RefKind::Spelled
clang::clangd::MATCHER_P
MATCHER_P(Named, N, "")
Definition: BackgroundIndexTests.cpp:29
PPCallbacks
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:162
clang::clangd::ParsedAST::getTokens
const syntax::TokenBuffer & getTokens() const
Tokens recorded while parsing the main file.
Definition: ParsedAST.h:103
Diags
CapturedDiags Diags
Definition: ConfigCompileTests.cpp:26
clang::clangd::ParsedAST::getLocalTopLevelDecls
ArrayRef< Decl * > getLocalTopLevelDecls()
This function returns top-level decls present in the main file of the AST.
Definition: ParsedAST.cpp:487
clang::clangd::Inclusion::HashOffset
unsigned HashOffset
Definition: Headers.h:58
clang::clangd::MockFS::Files
llvm::StringMap< std::string > Files
Definition: TestFS.h:41
clang::clangd::CompletionItemKind::Module
clang::clangd::ParsedAST::getSourceManager
SourceManager & getSourceManager()
Definition: ParsedAST.h:74
FileName
PathRef FileName
Definition: CodeComplete.cpp:1043
clang::clangd::MainFileMacros::UnknownMacros
std::vector< Range > UnknownMacros
Definition: CollectMacros.h:32
IgnoreDiags
IgnoringDiagConsumer IgnoreDiags
Definition: HeadersTests.cpp:128
clang::clangd::TestTU::HeaderCode
std::string HeaderCode
Definition: TestTU.h:52
clang::clangd::MATCHER
MATCHER(Declared, "")
Definition: BackgroundIndexTests.cpp:31
AST.h
ParsedAST.h
clang::clangd::ParsedAST::getMacros
const MainFileMacros & getMacros() const
Gets all macro references (definition, expansions) present in the main file, including those in the p...
Definition: ParsedAST.cpp:491