clang-tools  10.0.0
SourceCodeTests.cpp
Go to the documentation of this file.
1 //===-- SourceCodeTests.cpp ------------------------------------*- C++ -*-===//
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 #include "Annotations.h"
9 #include "Context.h"
10 #include "Protocol.h"
11 #include "SourceCode.h"
12 #include "TestTU.h"
13 #include "clang/Basic/LangOptions.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Format/Format.h"
16 #include "llvm/Support/Error.h"
17 #include "llvm/Support/raw_os_ostream.h"
18 #include "llvm/Testing/Support/Annotations.h"
19 #include "llvm/Testing/Support/Error.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include <tuple>
23 
24 namespace clang {
25 namespace clangd {
26 namespace {
27 
28 using llvm::Failed;
29 using llvm::HasValue;
30 
31 MATCHER_P2(Pos, Line, Col, "") {
32  return arg.line == int(Line) && arg.character == int(Col);
33 }
34 
35 MATCHER_P(MacroName, Name, "") { return arg.Name == Name; }
36 
37 /// A helper to make tests easier to read.
38 Position position(int Line, int Character) {
39  Position Pos;
40  Pos.line = Line;
41  Pos.character = Character;
42  return Pos;
43 }
44 
45 Range range(const std::pair<int, int> &P1, const std::pair<int, int> &P2) {
46  Range Range;
47  Range.start = position(P1.first, P1.second);
48  Range.end = position(P2.first, P2.second);
49  return Range;
50 }
51 
52 TEST(SourceCodeTests, lspLength) {
53  EXPECT_EQ(lspLength(""), 0UL);
54  EXPECT_EQ(lspLength("ascii"), 5UL);
55  // BMP
56  EXPECT_EQ(lspLength("↓"), 1UL);
57  EXPECT_EQ(lspLength("¥"), 1UL);
58  // astral
59  EXPECT_EQ(lspLength("😂"), 2UL);
60 
62  EXPECT_EQ(lspLength(""), 0UL);
63  EXPECT_EQ(lspLength("ascii"), 5UL);
64  // BMP
65  EXPECT_EQ(lspLength("↓"), 3UL);
66  EXPECT_EQ(lspLength("¥"), 2UL);
67  // astral
68  EXPECT_EQ(lspLength("😂"), 4UL);
69 
71  EXPECT_EQ(lspLength(""), 0UL);
72  EXPECT_EQ(lspLength("ascii"), 5UL);
73  // BMP
74  EXPECT_EQ(lspLength("↓"), 1UL);
75  EXPECT_EQ(lspLength("¥"), 1UL);
76  // astral
77  EXPECT_EQ(lspLength("😂"), 1UL);
78 }
79 
80 // The = → 🡆 below are ASCII (1 byte), BMP (3 bytes), and astral (4 bytes).
81 const char File[] = R"(0:0 = 0
82 1:0 → 8
83 2:0 🡆 18)";
84 struct Line {
85  unsigned Number;
86  unsigned Offset;
87  unsigned Length;
88 };
89 Line FileLines[] = {Line{0, 0, 7}, Line{1, 8, 9}, Line{2, 18, 11}};
90 
91 TEST(SourceCodeTests, PositionToOffset) {
92  // line out of bounds
93  EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed());
94  // first line
95  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)),
96  llvm::Failed()); // out of range
97  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)),
98  llvm::HasValue(0)); // first character
99  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)),
100  llvm::HasValue(3)); // middle character
101  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)),
102  llvm::HasValue(6)); // last character
103  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)),
104  llvm::HasValue(7)); // the newline itself
105  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false),
106  llvm::HasValue(7));
107  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)),
108  llvm::HasValue(7)); // out of range
109  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false),
110  llvm::Failed()); // out of range
111  // middle line
112  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)),
113  llvm::Failed()); // out of range
114  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)),
115  llvm::HasValue(8)); // first character
116  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)),
117  llvm::HasValue(11)); // middle character
118  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false),
119  llvm::HasValue(11));
120  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)),
121  llvm::HasValue(16)); // last character
122  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)),
123  llvm::HasValue(17)); // the newline itself
124  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)),
125  llvm::HasValue(17)); // out of range
126  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false),
127  llvm::Failed()); // out of range
128  // last line
129  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)),
130  llvm::Failed()); // out of range
131  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)),
132  llvm::HasValue(18)); // first character
133  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 3)),
134  llvm::HasValue(21)); // middle character
135  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5), false),
136  llvm::Failed()); // middle of surrogate pair
137  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5)),
138  llvm::HasValue(26)); // middle of surrogate pair
139  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 6), false),
140  llvm::HasValue(26)); // end of surrogate pair
141  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)),
142  llvm::HasValue(28)); // last character
143  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9)),
144  llvm::HasValue(29)); // EOF
145  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 10), false),
146  llvm::Failed()); // out of range
147  // line out of bounds
148  EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed());
149  EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), llvm::Failed());
150 
151  // Codepoints are similar, except near astral characters.
153  // line out of bounds
154  EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed());
155  // first line
156  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)),
157  llvm::Failed()); // out of range
158  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)),
159  llvm::HasValue(0)); // first character
160  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)),
161  llvm::HasValue(3)); // middle character
162  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)),
163  llvm::HasValue(6)); // last character
164  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)),
165  llvm::HasValue(7)); // the newline itself
166  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false),
167  llvm::HasValue(7));
168  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)),
169  llvm::HasValue(7)); // out of range
170  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false),
171  llvm::Failed()); // out of range
172  // middle line
173  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)),
174  llvm::Failed()); // out of range
175  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)),
176  llvm::HasValue(8)); // first character
177  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)),
178  llvm::HasValue(11)); // middle character
179  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false),
180  llvm::HasValue(11));
181  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)),
182  llvm::HasValue(16)); // last character
183  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)),
184  llvm::HasValue(17)); // the newline itself
185  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)),
186  llvm::HasValue(17)); // out of range
187  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false),
188  llvm::Failed()); // out of range
189  // last line
190  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)),
191  llvm::Failed()); // out of range
192  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)),
193  llvm::HasValue(18)); // first character
194  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 4)),
195  llvm::HasValue(22)); // Before astral character.
196  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5), false),
197  llvm::HasValue(26)); // after astral character
198  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 7)),
199  llvm::HasValue(28)); // last character
200  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)),
201  llvm::HasValue(29)); // EOF
202  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9), false),
203  llvm::Failed()); // out of range
204  // line out of bounds
205  EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed());
206  EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), llvm::Failed());
207 
208  // Test UTF-8, where transformations are trivial.
210  EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed());
211  EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed());
212  for (Line L : FileLines) {
213  EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, -1)),
214  llvm::Failed()); // out of range
215  for (unsigned I = 0; I <= L.Length; ++I)
216  EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, I)),
217  llvm::HasValue(L.Offset + I));
218  EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, L.Length+1)),
219  llvm::HasValue(L.Offset + L.Length));
220  EXPECT_THAT_EXPECTED(
221  positionToOffset(File, position(L.Number, L.Length + 1), false),
222  llvm::Failed()); // out of range
223  }
224 }
225 
226 TEST(SourceCodeTests, OffsetToPosition) {
227  EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file";
228  EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line";
229  EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line";
230  EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline";
231  EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line";
232  EXPECT_THAT(offsetToPosition(File, 12), Pos(1, 4)) << "before BMP char";
233  EXPECT_THAT(offsetToPosition(File, 13), Pos(1, 5)) << "in BMP char";
234  EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 5)) << "after BMP char";
235  EXPECT_THAT(offsetToPosition(File, 16), Pos(1, 6)) << "end of second line";
236  EXPECT_THAT(offsetToPosition(File, 17), Pos(1, 7)) << "second newline";
237  EXPECT_THAT(offsetToPosition(File, 18), Pos(2, 0)) << "start of last line";
238  EXPECT_THAT(offsetToPosition(File, 21), Pos(2, 3)) << "in last line";
239  EXPECT_THAT(offsetToPosition(File, 22), Pos(2, 4)) << "before astral char";
240  EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 6)) << "in astral char";
241  EXPECT_THAT(offsetToPosition(File, 26), Pos(2, 6)) << "after astral char";
242  EXPECT_THAT(offsetToPosition(File, 28), Pos(2, 8)) << "end of last line";
243  EXPECT_THAT(offsetToPosition(File, 29), Pos(2, 9)) << "EOF";
244  EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds";
245 
246  // Codepoints are similar, except near astral characters.
248  EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file";
249  EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line";
250  EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line";
251  EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline";
252  EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line";
253  EXPECT_THAT(offsetToPosition(File, 12), Pos(1, 4)) << "before BMP char";
254  EXPECT_THAT(offsetToPosition(File, 13), Pos(1, 5)) << "in BMP char";
255  EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 5)) << "after BMP char";
256  EXPECT_THAT(offsetToPosition(File, 16), Pos(1, 6)) << "end of second line";
257  EXPECT_THAT(offsetToPosition(File, 17), Pos(1, 7)) << "second newline";
258  EXPECT_THAT(offsetToPosition(File, 18), Pos(2, 0)) << "start of last line";
259  EXPECT_THAT(offsetToPosition(File, 21), Pos(2, 3)) << "in last line";
260  EXPECT_THAT(offsetToPosition(File, 22), Pos(2, 4)) << "before astral char";
261  EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 5)) << "in astral char";
262  EXPECT_THAT(offsetToPosition(File, 26), Pos(2, 5)) << "after astral char";
263  EXPECT_THAT(offsetToPosition(File, 28), Pos(2, 7)) << "end of last line";
264  EXPECT_THAT(offsetToPosition(File, 29), Pos(2, 8)) << "EOF";
265  EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 8)) << "out of bounds";
266 
268  for (Line L : FileLines) {
269  for (unsigned I = 0; I <= L.Length; ++I)
270  EXPECT_THAT(offsetToPosition(File, L.Offset + I), Pos(L.Number, I));
271  }
272  EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 11)) << "out of bounds";
273 }
274 
275 TEST(SourceCodeTests, IsRangeConsecutive) {
276  EXPECT_TRUE(isRangeConsecutive(range({2, 2}, {2, 3}), range({2, 3}, {2, 4})));
277  EXPECT_FALSE(
278  isRangeConsecutive(range({0, 2}, {0, 3}), range({2, 3}, {2, 4})));
279  EXPECT_FALSE(
280  isRangeConsecutive(range({2, 2}, {2, 3}), range({2, 4}, {2, 5})));
281 }
282 
283 TEST(SourceCodeTests, SourceLocationInMainFile) {
284  Annotations Source(R"cpp(
285  ^in^t ^foo
286  ^bar
287  ^baz ^() {} {} {} {} { }^
288 )cpp");
289 
290  SourceManagerForFile Owner("foo.cpp", Source.code());
291  SourceManager &SM = Owner.get();
292 
293  SourceLocation StartOfFile = SM.getLocForStartOfFile(SM.getMainFileID());
294  EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 0)),
295  HasValue(StartOfFile));
296  // End of file.
297  EXPECT_THAT_EXPECTED(
298  sourceLocationInMainFile(SM, position(4, 0)),
299  HasValue(StartOfFile.getLocWithOffset(Source.code().size())));
300  // Column number is too large.
301  EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 1)), Failed());
302  EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 100)),
303  Failed());
304  EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(4, 1)), Failed());
305  // Line number is too large.
306  EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(5, 0)), Failed());
307  // Check all positions mentioned in the test return valid results.
308  for (auto P : Source.points()) {
309  size_t Offset = llvm::cantFail(positionToOffset(Source.code(), P));
310  EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, P),
311  HasValue(StartOfFile.getLocWithOffset(Offset)));
312  }
313 }
314 
315 TEST(SourceCodeTests, GetBeginningOfIdentifier) {
316  std::string Preamble = R"cpp(
317 struct Bar { int func(); };
318 #define MACRO(X) void f() { X; }
319 Bar* bar;
320  )cpp";
321  // First ^ is the expected beginning, last is the search position.
322  for (const std::string &Text : std::vector<std::string>{
323  "int ^f^oo();", // inside identifier
324  "int ^foo();", // beginning of identifier
325  "int ^foo^();", // end of identifier
326  "int foo(^);", // non-identifier
327  "^int foo();", // beginning of file (can't back up)
328  "int ^f0^0();", // after a digit (lexing at N-1 is wrong)
329  "/^/ comments", // non-interesting token
330  "void f(int abc) { abc ^ ++; }", // whitespace
331  "void f(int abc) { ^abc^++; }", // range of identifier
332  "void f(int abc) { ++^abc^; }", // range of identifier
333  "void f(int abc) { ++^abc; }", // range of identifier
334  "void f(int abc) { ^+^+abc; }", // range of operator
335  "void f(int abc) { ^abc^ ++; }", // range of identifier
336  "void f(int abc) { abc ^++^; }", // range of operator
337  "void f(int abc) { ^++^ abc; }", // range of operator
338  "void f(int abc) { ++ ^abc^; }", // range of identifier
339  "void f(int abc) { ^++^/**/abc; }", // range of operator
340  "void f(int abc) { ++/**/^abc; }", // range of identifier
341  "void f(int abc) { ^abc^/**/++; }", // range of identifier
342  "void f(int abc) { abc/**/^++; }", // range of operator
343  "void f() {^ }", // outside of identifier and operator
344  "int ^λλ^λ();", // UTF-8 handled properly when backing up
345 
346  // identifier in macro arg
347  "MACRO(bar->^func())", // beginning of identifier
348  "MACRO(bar->^fun^c())", // inside identifier
349  "MACRO(bar->^func^())", // end of identifier
350  "MACRO(^bar->func())", // begin identifier
351  "MACRO(^bar^->func())", // end identifier
352  "^MACRO(bar->func())", // beginning of macro name
353  "^MAC^RO(bar->func())", // inside macro name
354  "^MACRO^(bar->func())", // end of macro name
355  }) {
356  std::string WithPreamble = Preamble + Text;
357  Annotations TestCase(WithPreamble);
358  auto AST = TestTU::withCode(TestCase.code()).build();
359  const auto &SourceMgr = AST.getSourceManager();
360  SourceLocation Actual = getBeginningOfIdentifier(
361  TestCase.points().back(), SourceMgr, AST.getLangOpts());
362  Position ActualPos = offsetToPosition(
363  TestCase.code(),
364  SourceMgr.getFileOffset(SourceMgr.getSpellingLoc(Actual)));
365  EXPECT_EQ(TestCase.points().front(), ActualPos) << Text;
366  }
367 }
368 
369 TEST(SourceCodeTests, CollectIdentifiers) {
370  auto Style = format::getLLVMStyle();
371  auto IDs = collectIdentifiers(R"cpp(
372  #include "a.h"
373  void foo() { int xyz; int abc = xyz; return foo(); }
374  )cpp",
375  Style);
376  EXPECT_EQ(IDs.size(), 7u);
377  EXPECT_EQ(IDs["include"], 1u);
378  EXPECT_EQ(IDs["void"], 1u);
379  EXPECT_EQ(IDs["int"], 2u);
380  EXPECT_EQ(IDs["xyz"], 2u);
381  EXPECT_EQ(IDs["abc"], 1u);
382  EXPECT_EQ(IDs["return"], 1u);
383  EXPECT_EQ(IDs["foo"], 2u);
384 }
385 
386 TEST(SourceCodeTests, CollectWords) {
387  auto Words = collectWords(R"cpp(
388  #define FIZZ_BUZZ
389  // this is a comment
390  std::string getSomeText() { return "magic word"; }
391  )cpp");
392  std::set<std::string> ActualWords(Words.keys().begin(), Words.keys().end());
393  std::set<std::string> ExpectedWords = {"define", "fizz", "buzz", "this",
394  "comment", "string", "some", "text",
395  "return", "magic", "word"};
396  EXPECT_EQ(ActualWords, ExpectedWords);
397 }
398 
399 TEST(SourceCodeTests, VisibleNamespaces) {
400  std::vector<std::pair<const char *, std::vector<std::string>>> Cases = {
401  {
402  R"cpp(
403  // Using directive resolved against enclosing namespaces.
404  using namespace foo;
405  namespace ns {
406  using namespace bar;
407  )cpp",
408  {"ns", "", "bar", "foo", "ns::bar"},
409  },
410  {
411  R"cpp(
412  // Don't include namespaces we've closed, ignore namespace aliases.
413  using namespace clang;
414  using std::swap;
415  namespace clang {
416  namespace clangd {}
417  namespace ll = ::llvm;
418  }
419  namespace clang {
420  )cpp",
421  {"clang", ""},
422  },
423  {
424  R"cpp(
425  // Using directives visible even if a namespace is reopened.
426  // Ignore anonymous namespaces.
427  namespace foo{ using namespace bar; }
428  namespace foo{ namespace {
429  )cpp",
430  {"foo", "", "bar", "foo::bar"},
431  },
432  {
433  R"cpp(
434  // Mismatched braces
435  namespace foo{}
436  }}}
437  namespace bar{
438  )cpp",
439  {"bar", ""},
440  },
441  {
442  R"cpp(
443  // Namespaces with multiple chunks.
444  namespace a::b {
445  using namespace c::d;
446  namespace e::f {
447  )cpp",
448  {
449  "a::b::e::f",
450  "",
451  "a",
452  "a::b",
453  "a::b::c::d",
454  "a::b::e",
455  "a::c::d",
456  "c::d",
457  },
458  },
459  {
460  "",
461  {""},
462  },
463  {
464  R"cpp(
465  // Parse until EOF
466  namespace bar{})cpp",
467  {""},
468  },
469  };
470  for (const auto& Case : Cases) {
471  EXPECT_EQ(Case.second,
472  visibleNamespaces(Case.first, format::getLLVMStyle()))
473  << Case.first;
474  }
475 }
476 
477 TEST(SourceCodeTests, GetMacros) {
478  Annotations Code(R"cpp(
479  #define MACRO 123
480  int abc = MA^CRO;
481  )cpp");
482  TestTU TU = TestTU::withCode(Code.code());
483  auto AST = TU.build();
484  auto Loc = getBeginningOfIdentifier(Code.point(), AST.getSourceManager(),
485  AST.getLangOpts());
486  auto Result = locateMacroAt(Loc, AST.getPreprocessor());
487  ASSERT_TRUE(Result);
488  EXPECT_THAT(*Result, MacroName("MACRO"));
489 }
490 
491 TEST(SourceCodeTests, IsInsideMainFile){
492  TestTU TU;
493  TU.HeaderCode = R"cpp(
494  #define DEFINE_CLASS(X) class X {};
495  #define DEFINE_YY DEFINE_CLASS(YY)
496 
497  class Header1 {};
498  DEFINE_CLASS(Header2)
499  class Header {};
500  )cpp";
501  TU.Code = R"cpp(
502  class Main1 {};
503  DEFINE_CLASS(Main2)
504  DEFINE_YY
505  class Main {};
506  )cpp";
507  TU.ExtraArgs.push_back("-DHeader=Header3");
508  TU.ExtraArgs.push_back("-DMain=Main3");
509  auto AST = TU.build();
510  const auto& SM = AST.getSourceManager();
511  auto DeclLoc = [&AST](llvm::StringRef Name) {
512  return findDecl(AST, Name).getLocation();
513  };
514  for (const auto *HeaderDecl : {"Header1", "Header2", "Header3"})
515  EXPECT_FALSE(isInsideMainFile(DeclLoc(HeaderDecl), SM));
516 
517  for (const auto *MainDecl : {"Main1", "Main2", "Main3", "YY"})
518  EXPECT_TRUE(isInsideMainFile(DeclLoc(MainDecl), SM));
519 }
520 
521 // Test for functions toHalfOpenFileRange and getHalfOpenFileRange
522 TEST(SourceCodeTests, HalfOpenFileRange) {
523  // Each marked range should be the file range of the decl with the same name
524  // and each name should be unique.
525  Annotations Test(R"cpp(
526  #define FOO(X, Y) int Y = ++X
527  #define BAR(X) X + 1
528  #define ECHO(X) X
529 
530  #define BUZZ BAZZ(ADD)
531  #define BAZZ(m) m(1)
532  #define ADD(a) int f = a + 1;
533  template<typename T>
534  class P {};
535 
536  int main() {
537  $a[[P<P<P<P<P<int>>>>> a]];
538  $b[[int b = 1]];
539  $c[[FOO(b, c)]];
540  $d[[FOO(BAR(BAR(b)), d)]];
541  // FIXME: We might want to select everything inside the outer ECHO.
542  ECHO(ECHO($e[[int) ECHO(e]]));
543  // Shouldn't crash.
544  $f[[BUZZ]];
545  }
546  )cpp");
547 
548  ParsedAST AST = TestTU::withCode(Test.code()).build();
549  llvm::errs() << Test.code();
550  const SourceManager &SM = AST.getSourceManager();
551  const LangOptions &LangOpts = AST.getLangOpts();
552  // Turn a SourceLocation into a pair of positions
553  auto SourceRangeToRange = [&SM](SourceRange SrcRange) {
554  return Range{sourceLocToPosition(SM, SrcRange.getBegin()),
555  sourceLocToPosition(SM, SrcRange.getEnd())};
556  };
557  auto CheckRange = [&](llvm::StringRef Name) {
558  const NamedDecl &Decl = findUnqualifiedDecl(AST, Name);
559  auto FileRange = toHalfOpenFileRange(SM, LangOpts, Decl.getSourceRange());
560  SCOPED_TRACE("Checking range: " + Name);
561  ASSERT_NE(FileRange, llvm::None);
562  Range HalfOpenRange = SourceRangeToRange(*FileRange);
563  EXPECT_EQ(HalfOpenRange, Test.ranges(Name)[0]);
564  };
565 
566  CheckRange("a");
567  CheckRange("b");
568  CheckRange("c");
569  CheckRange("d");
570  CheckRange("e");
571  CheckRange("f");
572 }
573 
574 TEST(SourceCodeTests, HalfOpenFileRangePathologicalPreprocessor) {
575  const char *Case = R"cpp(
576 #define MACRO while(1)
577  void test() {
578 [[#include "Expand.inc"
579  br^eak]];
580  }
581  )cpp";
582  Annotations Test(Case);
583  auto TU = TestTU::withCode(Test.code());
584  TU.AdditionalFiles["Expand.inc"] = "MACRO\n";
585  auto AST = TU.build();
586 
587  const auto &Func = cast<FunctionDecl>(findDecl(AST, "test"));
588  const auto &Body = cast<CompoundStmt>(Func.getBody());
589  const auto &Loop = cast<WhileStmt>(*Body->child_begin());
590  llvm::Optional<SourceRange> Range = toHalfOpenFileRange(
591  AST.getSourceManager(), AST.getLangOpts(), Loop->getSourceRange());
592  ASSERT_TRUE(Range) << "Failed to get file range";
593  EXPECT_EQ(AST.getSourceManager().getFileOffset(Range->getBegin()),
594  Test.llvm::Annotations::range().Begin);
595  EXPECT_EQ(AST.getSourceManager().getFileOffset(Range->getEnd()),
596  Test.llvm::Annotations::range().End);
597 }
598 
599 TEST(SourceCodeTests, IncludeHashLoc) {
600  const char *Case = R"cpp(
601 $foo^#include "foo.inc"
602 #define HEADER "bar.inc"
603  $bar^# include HEADER
604  )cpp";
605  Annotations Test(Case);
606  auto TU = TestTU::withCode(Test.code());
607  TU.AdditionalFiles["foo.inc"] = "int foo;\n";
608  TU.AdditionalFiles["bar.inc"] = "int bar;\n";
609  auto AST = TU.build();
610  const auto& SM = AST.getSourceManager();
611 
612  FileID Foo = SM.getFileID(findDecl(AST, "foo").getLocation());
613  EXPECT_EQ(SM.getFileOffset(includeHashLoc(Foo, SM)),
614  Test.llvm::Annotations::point("foo"));
615  FileID Bar = SM.getFileID(findDecl(AST, "bar").getLocation());
616  EXPECT_EQ(SM.getFileOffset(includeHashLoc(Bar, SM)),
617  Test.llvm::Annotations::point("bar"));
618 }
619 
620 TEST(SourceCodeTests, GetEligiblePoints) {
621  constexpr struct {
622  const char *Code;
623  const char *FullyQualifiedName;
624  const char *EnclosingNamespace;
625  } Cases[] = {
626  {R"cpp(// FIXME: We should also mark positions before and after
627  //declarations/definitions as eligible.
628  namespace ns1 {
629  namespace a { namespace ns2 {} }
630  namespace ns2 {^
631  void foo();
632  namespace {}
633  void bar() {}
634  namespace ns3 {}
635  class T {};
636  ^}
637  using namespace ns2;
638  })cpp",
639  "ns1::ns2::symbol", "ns1::ns2::"},
640  {R"cpp(
641  namespace ns1 {^
642  namespace a { namespace ns2 {} }
643  namespace b {}
644  namespace ns {}
645  ^})cpp",
646  "ns1::ns2::symbol", "ns1::"},
647  {R"cpp(
648  namespace x {
649  namespace a { namespace ns2 {} }
650  namespace b {}
651  namespace ns {}
652  }^)cpp",
653  "ns1::ns2::symbol", ""},
654  {R"cpp(
655  namespace ns1 {
656  namespace ns2 {^^}
657  namespace b {}
658  namespace ns2 {^^}
659  }
660  namespace ns1 {namespace ns2 {^^}})cpp",
661  "ns1::ns2::symbol", "ns1::ns2::"},
662  {R"cpp(
663  namespace ns1 {^
664  namespace ns {}
665  namespace b {}
666  namespace ns {}
667  ^}
668  namespace ns1 {^namespace ns {}^})cpp",
669  "ns1::ns2::symbol", "ns1::"},
670  };
671  for (auto Case : Cases) {
672  Annotations Test(Case.Code);
673 
674  auto Res = getEligiblePoints(Test.code(), Case.FullyQualifiedName,
675  format::getLLVMStyle());
676  EXPECT_THAT(Res.EligiblePoints, testing::ElementsAreArray(Test.points()))
677  << Test.code();
678  EXPECT_EQ(Res.EnclosingNamespace, Case.EnclosingNamespace) << Test.code();
679  }
680 }
681 
682 TEST(SourceCodeTests, IdentifierRanges) {
683  Annotations Code(R"cpp(
684  class [[Foo]] {};
685  // Foo
686  /* Foo */
687  void f([[Foo]]* foo1) {
688  [[Foo]] foo2;
689  auto S = [[Foo]]();
690 // cross-line identifier is not supported.
691 F\
692 o\
693 o foo2;
694  }
695  )cpp");
696  LangOptions LangOpts;
697  LangOpts.CPlusPlus = true;
698  EXPECT_EQ(Code.ranges(),
699  collectIdentifierRanges("Foo", Code.code(), LangOpts));
700 }
701 
702 TEST(SourceCodeTests, isHeaderFile) {
703  // Without lang options.
704  EXPECT_TRUE(isHeaderFile("foo.h"));
705  EXPECT_TRUE(isHeaderFile("foo.hh"));
706  EXPECT_TRUE(isHeaderFile("foo.hpp"));
707 
708  EXPECT_FALSE(isHeaderFile("foo.cpp"));
709  EXPECT_FALSE(isHeaderFile("foo.c++"));
710  EXPECT_FALSE(isHeaderFile("foo.cxx"));
711  EXPECT_FALSE(isHeaderFile("foo.cc"));
712  EXPECT_FALSE(isHeaderFile("foo.c"));
713  EXPECT_FALSE(isHeaderFile("foo.mm"));
714  EXPECT_FALSE(isHeaderFile("foo.m"));
715 
716  // With lang options
717  LangOptions LangOpts;
718  LangOpts.IsHeaderFile = true;
719  EXPECT_TRUE(isHeaderFile("string", LangOpts));
720  // Emulate cases where there is no "-x header" flag for a .h file, we still
721  // want to treat it as a header.
722  LangOpts.IsHeaderFile = false;
723  EXPECT_TRUE(isHeaderFile("header.h", LangOpts));
724 }
725 
726 } // namespace
727 } // namespace clangd
728 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
llvm::StringSet collectWords(llvm::StringRef Content)
Collects words from the source code.
Definition: SourceCode.cpp:949
OptionalMatcher< InnerMatcher > HasValue(const InnerMatcher &inner_matcher)
std::string Code
MATCHER_P(Named, N, "")
const FunctionDecl * Decl
unsigned Offset
size_t lspLength(llvm::StringRef Code)
Definition: SourceCode.cpp:131
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
Definition: SourceCode.cpp:534
SourceLocation getBeginningOfIdentifier(const Position &Pos, const SourceManager &SM, const LangOptions &LangOpts)
Get the beginning SourceLocation at a specified Pos in the main file.
Definition: SourceCode.cpp:277
Documents should not be synced at all.
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
Definition: TestTU.cpp:159
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
Definition: SourceCode.cpp:571
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const format::FormatStyle &Style)
Heuristically determine namespaces visible at a point, without parsing Code.
Definition: SourceCode.cpp:901
bool isRangeConsecutive(const Range &Left, const Range &Right)
Definition: SourceCode.cpp:670
std::string EnclosingNamespace
Position offsetToPosition(llvm::StringRef Code, size_t Offset)
Turn an offset in Code into a [line, column] pair.
Definition: SourceCode.cpp:188
TEST(BackgroundQueueTest, Priority)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:155
EligibleRegion getEligiblePoints(llvm::StringRef Code, llvm::StringRef FullyQualifiedName, const format::FormatStyle &Style)
Returns most eligible region to insert a definition for FullyQualifiedName in the Code...
static constexpr llvm::StringLiteral Name
Key< OffsetEncoding > kCurrentOffsetEncoding
Definition: SourceCode.cpp:124
Position Pos
Definition: SourceCode.cpp:772
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
Definition: SourceCode.cpp:200
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:33
llvm::Optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
Definition: SourceCode.cpp:538
SourceLocation includeHashLoc(FileID IncludedFile, const SourceManager &SM)
Returns the #include location through which IncludedFIle was loaded.
Definition: SourceCode.cpp:375
int line
Line position in a document (zero-based).
Definition: Protocol.h:129
const PreambleData * Preamble
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
unsigned Length
bool isHeaderFile(llvm::StringRef FileName, llvm::Optional< LangOptions > LangOpts)
Infers whether this is a header from the FileName and LangOpts (if presents).
std::vector< Range > collectIdentifierRanges(llvm::StringRef Identifier, llvm::StringRef Content, const LangOptions &LangOpts)
Collects all ranges of the given identifier in the source code.
Definition: SourceCode.cpp:746
llvm::StringMap< unsigned > collectIdentifiers(llvm::StringRef Content, const format::FormatStyle &Style)
Collects identifiers with counts in the source code.
Definition: SourceCode.cpp:735
llvm::Optional< DefinedMacro > locateMacroAt(SourceLocation Loc, Preprocessor &PP)
Gets the macro at a specified Loc.
Definition: SourceCode.cpp:987
llvm::StringMap< std::string > AdditionalFiles
Definition: TestTU.h:54
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition: TestTU.cpp:118