clang-tools  10.0.0
SelectionTests.cpp
Go to the documentation of this file.
1 //===-- SelectionTests.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 #include "Annotations.h"
9 #include "Selection.h"
10 #include "SourceCode.h"
11 #include "TestTU.h"
12 #include "clang/AST/Decl.h"
13 #include "llvm/Support/Casting.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16 
17 namespace clang {
18 namespace clangd {
19 namespace {
20 using ::testing::UnorderedElementsAreArray;
21 
22 SelectionTree makeSelectionTree(const StringRef MarkedCode, ParsedAST &AST) {
23  Annotations Test(MarkedCode);
24  switch (Test.points().size()) {
25  case 1: // Point selection.
26  return SelectionTree(AST.getASTContext(), AST.getTokens(),
27  cantFail(positionToOffset(Test.code(), Test.point())));
28  case 2: // Range selection.
29  return SelectionTree(
30  AST.getASTContext(), AST.getTokens(),
31  cantFail(positionToOffset(Test.code(), Test.points()[0])),
32  cantFail(positionToOffset(Test.code(), Test.points()[1])));
33  default:
34  ADD_FAILURE() << "Expected 1-2 points for selection.\n" << MarkedCode;
35  return SelectionTree(AST.getASTContext(), AST.getTokens(), 0u, 0u);
36  }
37 }
38 
39 Range nodeRange(const SelectionTree::Node *N, ParsedAST &AST) {
40  if (!N)
41  return Range{};
42  const SourceManager &SM = AST.getSourceManager();
43  const LangOptions &LangOpts = AST.getLangOpts();
44  StringRef Buffer = SM.getBufferData(SM.getMainFileID());
45  if (llvm::isa_and_nonnull<TranslationUnitDecl>(N->ASTNode.get<Decl>()))
46  return Range{Position{}, offsetToPosition(Buffer, Buffer.size())};
47  auto FileRange =
48  toHalfOpenFileRange(SM, LangOpts, N->ASTNode.getSourceRange());
49  assert(FileRange && "We should be able to get the File Range");
50  return Range{
51  offsetToPosition(Buffer, SM.getFileOffset(FileRange->getBegin())),
52  offsetToPosition(Buffer, SM.getFileOffset(FileRange->getEnd()))};
53 }
54 
55 std::string nodeKind(const SelectionTree::Node *N) {
56  return N ? N->kind() : "<null>";
57 }
58 
59 std::vector<const SelectionTree::Node *> allNodes(const SelectionTree &T) {
60  std::vector<const SelectionTree::Node *> Result = {&T.root()};
61  for (unsigned I = 0; I < Result.size(); ++I) {
62  const SelectionTree::Node *N = Result[I];
63  Result.insert(Result.end(), N->Children.begin(), N->Children.end());
64  }
65  return Result;
66 }
67 
68 // Returns true if Common is a descendent of Root.
69 // Verifies nothing is selected above Common.
70 bool verifyCommonAncestor(const SelectionTree::Node &Root,
71  const SelectionTree::Node *Common,
72  StringRef MarkedCode) {
73  if (&Root == Common)
74  return true;
75  if (Root.Selected)
76  ADD_FAILURE() << "Selected nodes outside common ancestor\n" << MarkedCode;
77  bool Seen = false;
78  for (const SelectionTree::Node *Child : Root.Children)
79  if (verifyCommonAncestor(*Child, Common, MarkedCode)) {
80  if (Seen)
81  ADD_FAILURE() << "Saw common ancestor twice\n" << MarkedCode;
82  Seen = true;
83  }
84  return Seen;
85 }
86 
87 TEST(SelectionTest, CommonAncestor) {
88  struct Case {
89  // Selection is between ^marks^.
90  // common ancestor marked with a [[range]].
91  const char *Code;
92  const char *CommonAncestorKind;
93  };
94  Case Cases[] = {
95  {
96  R"cpp(
97  template <typename T>
98  int x = [[T::^U::]]ccc();
99  )cpp",
100  "NestedNameSpecifierLoc",
101  },
102  {
103  R"cpp(
104  struct AAA { struct BBB { static int ccc(); };};
105  int x = AAA::[[B^B^B]]::ccc();
106  )cpp",
107  "RecordTypeLoc",
108  },
109  {
110  R"cpp(
111  struct AAA { struct BBB { static int ccc(); };};
112  int x = AAA::[[B^BB^]]::ccc();
113  )cpp",
114  "RecordTypeLoc",
115  },
116  {
117  R"cpp(
118  struct AAA { struct BBB { static int ccc(); };};
119  int x = [[AAA::BBB::c^c^c]]();
120  )cpp",
121  "DeclRefExpr",
122  },
123  {
124  R"cpp(
125  struct AAA { struct BBB { static int ccc(); };};
126  int x = [[AAA::BBB::cc^c(^)]];
127  )cpp",
128  "CallExpr",
129  },
130 
131  {
132  R"cpp(
133  void foo() { [[if (1^11) { return; } else {^ }]] }
134  )cpp",
135  "IfStmt",
136  },
137  {
138  R"cpp(
139  int x(int);
140  #define M(foo) x(foo)
141  int a = 42;
142  int b = M([[^a]]);
143  )cpp",
144  "DeclRefExpr",
145  },
146  {
147  R"cpp(
148  void foo();
149  #define CALL_FUNCTION(X) X()
150  void bar() { CALL_FUNCTION([[f^o^o]]); }
151  )cpp",
152  "DeclRefExpr",
153  },
154  {
155  R"cpp(
156  void foo();
157  #define CALL_FUNCTION(X) X()
158  void bar() { [[CALL_FUNC^TION(fo^o)]]; }
159  )cpp",
160  "CallExpr",
161  },
162  {
163  R"cpp(
164  void foo();
165  #define CALL_FUNCTION(X) X()
166  void bar() { [[C^ALL_FUNC^TION(foo)]]; }
167  )cpp",
168  "CallExpr",
169  },
170  {
171  R"cpp(
172  void foo();
173  #define CALL_FUNCTION(X) X^()^
174  void bar() { CALL_FUNCTION(foo); }
175  )cpp",
176  nullptr,
177  },
178  {
179  R"cpp(
180  struct S { S(const char*); };
181  S [[s ^= "foo"]];
182  )cpp",
183  "CXXConstructExpr",
184  },
185  {
186  R"cpp(
187  struct S { S(const char*); };
188  [[S ^s = "foo"]];
189  )cpp",
190  "VarDecl",
191  },
192  {
193  R"cpp(
194  [[^void]] (*S)(int) = nullptr;
195  )cpp",
196  "BuiltinTypeLoc",
197  },
198  {
199  R"cpp(
200  [[void (*S)^(int)]] = nullptr;
201  )cpp",
202  "FunctionProtoTypeLoc",
203  },
204  {
205  R"cpp(
206  [[void (^*S)(int)]] = nullptr;
207  )cpp",
208  "FunctionProtoTypeLoc",
209  },
210  {
211  R"cpp(
212  [[void (*^S)(int) = nullptr]];
213  )cpp",
214  "VarDecl",
215  },
216  {
217  R"cpp(
218  [[void ^(*S)(int)]] = nullptr;
219  )cpp",
220  "FunctionProtoTypeLoc",
221  },
222  {
223  R"cpp(
224  struct S {
225  int foo() const;
226  int bar() { return [[f^oo]](); }
227  };
228  )cpp",
229  "MemberExpr", // Not implicit CXXThisExpr, or its implicit cast!
230  },
231  {
232  R"cpp(
233  auto lambda = [](const char*){ return 0; };
234  int x = lambda([["y^"]]);
235  )cpp",
236  "StringLiteral", // Not DeclRefExpr to operator()!
237  },
238 
239  // Point selections.
240  {"void foo() { [[^foo]](); }", "DeclRefExpr"},
241  {"void foo() { [[f^oo]](); }", "DeclRefExpr"},
242  {"void foo() { [[fo^o]](); }", "DeclRefExpr"},
243  {"void foo() { [[foo^()]]; }", "CallExpr"},
244  {"void foo() { [[foo^]] (); }", "DeclRefExpr"},
245  {"int bar; void foo() [[{ foo (); }]]^", "CompoundStmt"},
246  {"int x = [[42]]^;", "IntegerLiteral"},
247 
248  // Ignores whitespace, comments, and semicolons in the selection.
249  {"void foo() { [[foo^()]]; /*comment*/^}", "CallExpr"},
250 
251  // Tricky case: FunctionTypeLoc in FunctionDecl has a hole in it.
252  {"[[^void]] foo();", "BuiltinTypeLoc"},
253  {"[[void foo^()]];", "FunctionProtoTypeLoc"},
254  {"[[^void foo^()]];", "FunctionDecl"},
255  {"[[void ^foo()]];", "FunctionDecl"},
256  // Tricky case: two VarDecls share a specifier.
257  {"[[int ^a]], b;", "VarDecl"},
258  {"[[int a, ^b]];", "VarDecl"},
259  // Tricky case: CXXConstructExpr wants to claim the whole init range.
260  {
261  R"cpp(
262  class X { X(int); };
263  class Y {
264  X x;
265  Y() : [[^x(4)]] {}
266  };
267  )cpp",
268  "CXXCtorInitializer", // Not the CXXConstructExpr!
269  },
270  // Tricky case: anonymous struct is a sibling of the VarDecl.
271  {"[[st^ruct {int x;}]] y;", "CXXRecordDecl"},
272  {"[[struct {int x;} ^y]];", "VarDecl"},
273  {"struct {[[int ^x]];} y;", "FieldDecl"},
274  // FIXME: the AST has no location info for qualifiers.
275  {"const [[a^uto]] x = 42;", "AutoTypeLoc"},
276  {"[[co^nst auto x = 42]];", "VarDecl"},
277 
278  {"^", nullptr},
279  {"void foo() { [[foo^^]] (); }", "DeclRefExpr"},
280 
281  // FIXME: Ideally we'd get a declstmt or the VarDecl itself here.
282  // This doesn't happen now; the RAV doesn't traverse a node containing ;.
283  {"int x = 42;^", nullptr},
284 
285  // Common ancestor is logically TUDecl, but we never return that.
286  {"^int x; int y;^", nullptr},
287 
288  // Node types that have caused problems in the past.
289  {"template <typename T> void foo() { [[^T]] t; }",
290  "TemplateTypeParmTypeLoc"},
291 
292  // No crash
293  {
294  R"cpp(
295  template <class T> struct Foo {};
296  template <[[template<class> class /*cursor here*/^U]]>
297  struct Foo<U<int>*> {};
298  )cpp",
299  "TemplateTemplateParmDecl"},
300 
301  // Foreach has a weird AST, ensure we can select parts of the range init.
302  // This used to fail, because the DeclStmt for C claimed the whole range.
303  {
304  R"cpp(
305  struct Str {
306  const char *begin();
307  const char *end();
308  };
309  Str makeStr(const char*);
310  void loop() {
311  for (const char* C : [[mak^eStr("foo"^)]])
312  ;
313  }
314  )cpp",
315  "CallExpr"},
316 
317  // User-defined literals are tricky: is 12_i one token or two?
318  // For now we treat it as one, and the UserDefinedLiteral as a leaf.
319  {
320  R"cpp(
321  struct Foo{};
322  Foo operator""_ud(unsigned long long);
323  Foo x = [[^12_ud]];
324  )cpp",
325  "UserDefinedLiteral"},
326  {
327  R"cpp(
328  int a;
329  decltype([[^a]] + a) b;
330  )cpp",
331  "DeclRefExpr"},
332  };
333  for (const Case &C : Cases) {
334  Annotations Test(C.Code);
335 
336  TestTU TU;
337  TU.Code = Test.code();
338 
339  // FIXME: Auto-completion in a template requires disabling delayed template
340  // parsing.
341  TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
342 
343  auto AST = TU.build();
344  auto T = makeSelectionTree(C.Code, AST);
345  EXPECT_EQ("TranslationUnitDecl", nodeKind(&T.root())) << C.Code;
346 
347  if (Test.ranges().empty()) {
348  // If no [[range]] is marked in the example, there should be no selection.
349  EXPECT_FALSE(T.commonAncestor()) << C.Code << "\n" << T;
350  } else {
351  // If there is an expected selection, common ancestor should exist
352  // with the appropriate node type.
353  EXPECT_EQ(C.CommonAncestorKind, nodeKind(T.commonAncestor()))
354  << C.Code << "\n"
355  << T;
356  // Convert the reported common ancestor to a range and verify it.
357  EXPECT_EQ(nodeRange(T.commonAncestor(), AST), Test.range())
358  << C.Code << "\n"
359  << T;
360 
361  // Check that common ancestor is reachable on exactly one path from root,
362  // and no nodes outside it are selected.
363  EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code))
364  << C.Code;
365  }
366  }
367 }
368 
369 // Regression test: this used to match the injected X, not the outer X.
370 TEST(SelectionTest, InjectedClassName) {
371  const char* Code = "struct ^X { int x; };";
372  auto AST = TestTU::withCode(Annotations(Code).code()).build();
373  auto T = makeSelectionTree(Code, AST);
374  ASSERT_EQ("CXXRecordDecl", nodeKind(T.commonAncestor())) << T;
375  auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<Decl>());
376  EXPECT_FALSE(D->isInjectedClassName());
377 }
378 
379 // FIXME: Doesn't select the binary operator node in
380 // #define FOO(X) X + 1
381 // int a, b = [[FOO(a)]];
382 TEST(SelectionTest, Selected) {
383  // Selection with ^marks^.
384  // Partially selected nodes marked with a [[range]].
385  // Completely selected nodes marked with a $C[[range]].
386  const char *Cases[] = {
387  R"cpp( int abc, xyz = [[^ab^c]]; )cpp",
388  R"cpp( int abc, xyz = [[a^bc^]]; )cpp",
389  R"cpp( int abc, xyz = $C[[^abc^]]; )cpp",
390  R"cpp(
391  void foo() {
392  [[if ([[1^11]]) $C[[{
393  $C[[return]];
394  }]] else [[{^
395  }]]]]
396  char z;
397  }
398  )cpp",
399  R"cpp(
400  template <class T>
401  struct unique_ptr {};
402  void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {}
403  )cpp",
404  R"cpp(int a = [[5 >^> 1]];)cpp",
405  R"cpp(
406  #define ECHO(X) X
407  ECHO(EC^HO($C[[int]]) EC^HO(a));
408  )cpp",
409  R"cpp( $C[[^$C[[int]] a^]]; )cpp",
410  R"cpp( $C[[^$C[[int]] a = $C[[5]]^]]; )cpp",
411  };
412  for (const char *C : Cases) {
413  Annotations Test(C);
414  auto AST = TestTU::withCode(Test.code()).build();
415  auto T = makeSelectionTree(C, AST);
416 
417  std::vector<Range> Complete, Partial;
418  for (const SelectionTree::Node *N : allNodes(T))
419  if (N->Selected == SelectionTree::Complete)
420  Complete.push_back(nodeRange(N, AST));
421  else if (N->Selected == SelectionTree::Partial)
422  Partial.push_back(nodeRange(N, AST));
423  EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges("C"))) << C;
424  EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) << C;
425  }
426 }
427 
428 TEST(SelectionTest, PathologicalPreprocessor) {
429  const char *Case = R"cpp(
430 #define MACRO while(1)
431  void test() {
432 #include "Expand.inc"
433  br^eak;
434  }
435  )cpp";
436  Annotations Test(Case);
437  auto TU = TestTU::withCode(Test.code());
438  TU.AdditionalFiles["Expand.inc"] = "MACRO\n";
439  auto AST = TU.build();
440  EXPECT_THAT(AST.getDiagnostics(), ::testing::IsEmpty());
441  auto T = makeSelectionTree(Case, AST);
442 
443  EXPECT_EQ("BreakStmt", T.commonAncestor()->kind());
444  EXPECT_EQ("WhileStmt", T.commonAncestor()->Parent->kind());
445 }
446 
447 TEST(SelectionTest, IncludedFile) {
448  const char *Case = R"cpp(
449  void test() {
450 #include "Exp^and.inc"
451  break;
452  }
453  )cpp";
454  Annotations Test(Case);
455  auto TU = TestTU::withCode(Test.code());
456  TU.AdditionalFiles["Expand.inc"] = "while(1)\n";
457  auto AST = TU.build();
458  auto T = makeSelectionTree(Case, AST);
459 
460  EXPECT_EQ("WhileStmt", T.commonAncestor()->kind());
461 }
462 
463 TEST(SelectionTest, MacroArgExpansion) {
464  // If a macro arg is expanded several times, we consider them all selected.
465  const char *Case = R"cpp(
466  int mul(int, int);
467  #define SQUARE(X) mul(X, X);
468  int nine = SQUARE(^3);
469  )cpp";
470  Annotations Test(Case);
471  auto AST = TestTU::withCode(Test.code()).build();
472  auto T = makeSelectionTree(Case, AST);
473  // Unfortunately, this makes the common ancestor the CallExpr...
474  // FIXME: hack around this by picking one?
475  EXPECT_EQ("CallExpr", T.commonAncestor()->kind());
476  EXPECT_FALSE(T.commonAncestor()->Selected);
477  EXPECT_EQ(2u, T.commonAncestor()->Children.size());
478  for (const auto* N : T.commonAncestor()->Children) {
479  EXPECT_EQ("IntegerLiteral", N->kind());
480  EXPECT_TRUE(N->Selected);
481  }
482 
483  // Verify that the common assert() macro doesn't suffer from this.
484  // (This is because we don't associate the stringified token with the arg).
485  Case = R"cpp(
486  void die(const char*);
487  #define assert(x) (x ? (void)0 : die(#x)
488  void foo() { assert(^42); }
489  )cpp";
490  Test = Annotations(Case);
491  AST = TestTU::withCode(Test.code()).build();
492  T = makeSelectionTree(Case, AST);
493 
494  EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
495 }
496 
497 TEST(SelectionTest, Implicit) {
498  const char* Test = R"cpp(
499  struct S { S(const char*); };
500  int f(S);
501  int x = f("^");
502  )cpp";
503  auto AST = TestTU::withCode(Annotations(Test).code()).build();
504  auto T = makeSelectionTree(Test, AST);
505 
506  const SelectionTree::Node *Str = T.commonAncestor();
507  EXPECT_EQ("StringLiteral", nodeKind(Str)) << "Implicit selected?";
508  EXPECT_EQ("ImplicitCastExpr", nodeKind(Str->Parent));
509  EXPECT_EQ("CXXConstructExpr", nodeKind(Str->Parent->Parent));
510  EXPECT_EQ(Str, &Str->Parent->Parent->ignoreImplicit())
511  << "Didn't unwrap " << nodeKind(&Str->Parent->Parent->ignoreImplicit());
512 
513  EXPECT_EQ("CXXConstructExpr", nodeKind(&Str->outerImplicit()));
514 }
515 
516 } // namespace
517 } // namespace clangd
518 } // namespace clang
ParsedAST build() const
Definition: TestTU.cpp:22
std::string Code
const FunctionDecl * Decl
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
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
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
SelectionTree::Selection Selected
Definition: Selection.cpp:315
llvm::StringMap< std::string > AdditionalFiles
Definition: TestTU.h:54