150
|
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"
|
173
|
12 #include "support/TestTracer.h"
|
150
|
13 #include "clang/AST/Decl.h"
|
|
14 #include "llvm/Support/Casting.h"
|
|
15 #include "gmock/gmock.h"
|
|
16 #include "gtest/gtest.h"
|
|
17
|
|
18 namespace clang {
|
|
19 namespace clangd {
|
|
20 namespace {
|
221
|
21 using ::testing::ElementsAreArray;
|
150
|
22 using ::testing::UnorderedElementsAreArray;
|
|
23
|
173
|
24 // Create a selection tree corresponding to a point or pair of points.
|
|
25 // This uses the precisely-defined createRight semantics. The fuzzier
|
|
26 // createEach is tested separately.
|
150
|
27 SelectionTree makeSelectionTree(const StringRef MarkedCode, ParsedAST &AST) {
|
|
28 Annotations Test(MarkedCode);
|
|
29 switch (Test.points().size()) {
|
173
|
30 case 1: { // Point selection.
|
|
31 unsigned Offset = cantFail(positionToOffset(Test.code(), Test.point()));
|
|
32 return SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
|
|
33 Offset, Offset);
|
|
34 }
|
150
|
35 case 2: // Range selection.
|
173
|
36 return SelectionTree::createRight(
|
150
|
37 AST.getASTContext(), AST.getTokens(),
|
|
38 cantFail(positionToOffset(Test.code(), Test.points()[0])),
|
|
39 cantFail(positionToOffset(Test.code(), Test.points()[1])));
|
|
40 default:
|
|
41 ADD_FAILURE() << "Expected 1-2 points for selection.\n" << MarkedCode;
|
173
|
42 return SelectionTree::createRight(AST.getASTContext(), AST.getTokens(), 0u,
|
|
43 0u);
|
150
|
44 }
|
|
45 }
|
|
46
|
|
47 Range nodeRange(const SelectionTree::Node *N, ParsedAST &AST) {
|
|
48 if (!N)
|
|
49 return Range{};
|
|
50 const SourceManager &SM = AST.getSourceManager();
|
|
51 const LangOptions &LangOpts = AST.getLangOpts();
|
|
52 StringRef Buffer = SM.getBufferData(SM.getMainFileID());
|
|
53 if (llvm::isa_and_nonnull<TranslationUnitDecl>(N->ASTNode.get<Decl>()))
|
|
54 return Range{Position{}, offsetToPosition(Buffer, Buffer.size())};
|
|
55 auto FileRange =
|
|
56 toHalfOpenFileRange(SM, LangOpts, N->ASTNode.getSourceRange());
|
|
57 assert(FileRange && "We should be able to get the File Range");
|
|
58 return Range{
|
|
59 offsetToPosition(Buffer, SM.getFileOffset(FileRange->getBegin())),
|
|
60 offsetToPosition(Buffer, SM.getFileOffset(FileRange->getEnd()))};
|
|
61 }
|
|
62
|
|
63 std::string nodeKind(const SelectionTree::Node *N) {
|
|
64 return N ? N->kind() : "<null>";
|
|
65 }
|
|
66
|
|
67 std::vector<const SelectionTree::Node *> allNodes(const SelectionTree &T) {
|
|
68 std::vector<const SelectionTree::Node *> Result = {&T.root()};
|
|
69 for (unsigned I = 0; I < Result.size(); ++I) {
|
|
70 const SelectionTree::Node *N = Result[I];
|
|
71 Result.insert(Result.end(), N->Children.begin(), N->Children.end());
|
|
72 }
|
|
73 return Result;
|
|
74 }
|
|
75
|
|
76 // Returns true if Common is a descendent of Root.
|
|
77 // Verifies nothing is selected above Common.
|
|
78 bool verifyCommonAncestor(const SelectionTree::Node &Root,
|
|
79 const SelectionTree::Node *Common,
|
|
80 StringRef MarkedCode) {
|
|
81 if (&Root == Common)
|
|
82 return true;
|
|
83 if (Root.Selected)
|
|
84 ADD_FAILURE() << "Selected nodes outside common ancestor\n" << MarkedCode;
|
|
85 bool Seen = false;
|
|
86 for (const SelectionTree::Node *Child : Root.Children)
|
|
87 if (verifyCommonAncestor(*Child, Common, MarkedCode)) {
|
|
88 if (Seen)
|
|
89 ADD_FAILURE() << "Saw common ancestor twice\n" << MarkedCode;
|
|
90 Seen = true;
|
|
91 }
|
|
92 return Seen;
|
|
93 }
|
|
94
|
|
95 TEST(SelectionTest, CommonAncestor) {
|
|
96 struct Case {
|
|
97 // Selection is between ^marks^.
|
|
98 // common ancestor marked with a [[range]].
|
|
99 const char *Code;
|
|
100 const char *CommonAncestorKind;
|
|
101 };
|
|
102 Case Cases[] = {
|
|
103 {
|
|
104 R"cpp(
|
|
105 template <typename T>
|
|
106 int x = [[T::^U::]]ccc();
|
|
107 )cpp",
|
|
108 "NestedNameSpecifierLoc",
|
|
109 },
|
|
110 {
|
|
111 R"cpp(
|
|
112 struct AAA { struct BBB { static int ccc(); };};
|
|
113 int x = AAA::[[B^B^B]]::ccc();
|
|
114 )cpp",
|
|
115 "RecordTypeLoc",
|
|
116 },
|
|
117 {
|
|
118 R"cpp(
|
|
119 struct AAA { struct BBB { static int ccc(); };};
|
|
120 int x = AAA::[[B^BB^]]::ccc();
|
|
121 )cpp",
|
|
122 "RecordTypeLoc",
|
|
123 },
|
|
124 {
|
|
125 R"cpp(
|
|
126 struct AAA { struct BBB { static int ccc(); };};
|
|
127 int x = [[AAA::BBB::c^c^c]]();
|
|
128 )cpp",
|
|
129 "DeclRefExpr",
|
|
130 },
|
|
131 {
|
|
132 R"cpp(
|
|
133 struct AAA { struct BBB { static int ccc(); };};
|
|
134 int x = [[AAA::BBB::cc^c(^)]];
|
|
135 )cpp",
|
|
136 "CallExpr",
|
|
137 },
|
|
138
|
|
139 {
|
|
140 R"cpp(
|
|
141 void foo() { [[if (1^11) { return; } else {^ }]] }
|
|
142 )cpp",
|
|
143 "IfStmt",
|
|
144 },
|
|
145 {
|
|
146 R"cpp(
|
|
147 int x(int);
|
|
148 #define M(foo) x(foo)
|
|
149 int a = 42;
|
|
150 int b = M([[^a]]);
|
|
151 )cpp",
|
|
152 "DeclRefExpr",
|
|
153 },
|
|
154 {
|
|
155 R"cpp(
|
|
156 void foo();
|
|
157 #define CALL_FUNCTION(X) X()
|
|
158 void bar() { CALL_FUNCTION([[f^o^o]]); }
|
|
159 )cpp",
|
|
160 "DeclRefExpr",
|
|
161 },
|
|
162 {
|
|
163 R"cpp(
|
|
164 void foo();
|
|
165 #define CALL_FUNCTION(X) X()
|
|
166 void bar() { [[CALL_FUNC^TION(fo^o)]]; }
|
|
167 )cpp",
|
|
168 "CallExpr",
|
|
169 },
|
|
170 {
|
|
171 R"cpp(
|
|
172 void foo();
|
|
173 #define CALL_FUNCTION(X) X()
|
|
174 void bar() { [[C^ALL_FUNC^TION(foo)]]; }
|
|
175 )cpp",
|
|
176 "CallExpr",
|
|
177 },
|
|
178 {
|
|
179 R"cpp(
|
|
180 void foo();
|
221
|
181 #^define CALL_FUNCTION(X) X(^)
|
150
|
182 void bar() { CALL_FUNCTION(foo); }
|
|
183 )cpp",
|
|
184 nullptr,
|
|
185 },
|
|
186 {
|
|
187 R"cpp(
|
221
|
188 void foo();
|
|
189 #define CALL_FUNCTION(X) X()
|
|
190 void bar() { CALL_FUNCTION(foo^)^; }
|
|
191 )cpp",
|
|
192 nullptr,
|
|
193 },
|
|
194 {
|
|
195 R"cpp(
|
|
196 namespace ns {
|
|
197 #if 0
|
|
198 void fo^o() {}
|
|
199 #endif
|
|
200 }
|
|
201 )cpp",
|
|
202 nullptr,
|
|
203 },
|
|
204 {
|
|
205 R"cpp(
|
236
|
206 #define TARGET void foo()
|
|
207 [[TAR^GET{ return; }]]
|
|
208 )cpp",
|
|
209 "FunctionDecl",
|
|
210 },
|
|
211 {
|
|
212 R"cpp(
|
150
|
213 struct S { S(const char*); };
|
236
|
214 [[S s ^= "foo"]];
|
150
|
215 )cpp",
|
236
|
216 // The AST says a CXXConstructExpr covers the = sign in C++14.
|
|
217 // But we consider CXXConstructExpr to only own brackets.
|
|
218 // (It's not the interesting constructor anyway, just S(&&)).
|
|
219 "VarDecl",
|
150
|
220 },
|
|
221 {
|
|
222 R"cpp(
|
|
223 struct S { S(const char*); };
|
|
224 [[S ^s = "foo"]];
|
|
225 )cpp",
|
|
226 "VarDecl",
|
|
227 },
|
|
228 {
|
|
229 R"cpp(
|
|
230 [[^void]] (*S)(int) = nullptr;
|
|
231 )cpp",
|
|
232 "BuiltinTypeLoc",
|
|
233 },
|
|
234 {
|
|
235 R"cpp(
|
|
236 [[void (*S)^(int)]] = nullptr;
|
|
237 )cpp",
|
|
238 "FunctionProtoTypeLoc",
|
|
239 },
|
|
240 {
|
|
241 R"cpp(
|
|
242 [[void (^*S)(int)]] = nullptr;
|
|
243 )cpp",
|
236
|
244 "PointerTypeLoc",
|
150
|
245 },
|
|
246 {
|
|
247 R"cpp(
|
|
248 [[void (*^S)(int) = nullptr]];
|
|
249 )cpp",
|
|
250 "VarDecl",
|
|
251 },
|
|
252 {
|
|
253 R"cpp(
|
|
254 [[void ^(*S)(int)]] = nullptr;
|
|
255 )cpp",
|
236
|
256 "ParenTypeLoc",
|
150
|
257 },
|
|
258 {
|
|
259 R"cpp(
|
|
260 struct S {
|
|
261 int foo() const;
|
|
262 int bar() { return [[f^oo]](); }
|
|
263 };
|
|
264 )cpp",
|
|
265 "MemberExpr", // Not implicit CXXThisExpr, or its implicit cast!
|
|
266 },
|
|
267 {
|
|
268 R"cpp(
|
|
269 auto lambda = [](const char*){ return 0; };
|
|
270 int x = lambda([["y^"]]);
|
|
271 )cpp",
|
|
272 "StringLiteral", // Not DeclRefExpr to operator()!
|
|
273 },
|
221
|
274 {
|
|
275 R"cpp(
|
|
276 struct Foo {};
|
|
277 struct Bar : [[v^ir^tual private Foo]] {};
|
|
278 )cpp",
|
|
279 "CXXBaseSpecifier",
|
|
280 },
|
|
281 {
|
|
282 R"cpp(
|
|
283 struct Foo {};
|
|
284 struct Bar : private [[Fo^o]] {};
|
|
285 )cpp",
|
|
286 "RecordTypeLoc",
|
|
287 },
|
|
288 {
|
|
289 R"cpp(
|
|
290 struct Foo {};
|
|
291 struct Bar : [[Fo^o]] {};
|
|
292 )cpp",
|
|
293 "RecordTypeLoc",
|
|
294 },
|
150
|
295
|
|
296 // Point selections.
|
|
297 {"void foo() { [[^foo]](); }", "DeclRefExpr"},
|
|
298 {"void foo() { [[f^oo]](); }", "DeclRefExpr"},
|
|
299 {"void foo() { [[fo^o]](); }", "DeclRefExpr"},
|
|
300 {"void foo() { [[foo^()]]; }", "CallExpr"},
|
|
301 {"void foo() { [[foo^]] (); }", "DeclRefExpr"},
|
|
302 {"int bar; void foo() [[{ foo (); }]]^", "CompoundStmt"},
|
|
303 {"int x = [[42]]^;", "IntegerLiteral"},
|
|
304
|
|
305 // Ignores whitespace, comments, and semicolons in the selection.
|
|
306 {"void foo() { [[foo^()]]; /*comment*/^}", "CallExpr"},
|
|
307
|
|
308 // Tricky case: FunctionTypeLoc in FunctionDecl has a hole in it.
|
|
309 {"[[^void]] foo();", "BuiltinTypeLoc"},
|
|
310 {"[[void foo^()]];", "FunctionProtoTypeLoc"},
|
|
311 {"[[^void foo^()]];", "FunctionDecl"},
|
|
312 {"[[void ^foo()]];", "FunctionDecl"},
|
|
313 // Tricky case: two VarDecls share a specifier.
|
|
314 {"[[int ^a]], b;", "VarDecl"},
|
|
315 {"[[int a, ^b]];", "VarDecl"},
|
|
316 // Tricky case: CXXConstructExpr wants to claim the whole init range.
|
|
317 {
|
|
318 R"cpp(
|
|
319 struct X { X(int); };
|
|
320 class Y {
|
|
321 X x;
|
|
322 Y() : [[^x(4)]] {}
|
|
323 };
|
|
324 )cpp",
|
|
325 "CXXCtorInitializer", // Not the CXXConstructExpr!
|
|
326 },
|
|
327 // Tricky case: anonymous struct is a sibling of the VarDecl.
|
|
328 {"[[st^ruct {int x;}]] y;", "CXXRecordDecl"},
|
|
329 {"[[struct {int x;} ^y]];", "VarDecl"},
|
|
330 {"struct {[[int ^x]];} y;", "FieldDecl"},
|
236
|
331
|
|
332 // Tricky case: nested ArrayTypeLocs have the same token range.
|
|
333 {"const int x = 1, y = 2; int array[^[[x]]][10][y];", "DeclRefExpr"},
|
|
334 {"const int x = 1, y = 2; int array[x][10][^[[y]]];", "DeclRefExpr"},
|
|
335 {"const int x = 1, y = 2; int array[x][^[[10]]][y];", "IntegerLiteral"},
|
|
336 {"const int x = 1, y = 2; [[i^nt]] array[x][10][y];", "BuiltinTypeLoc"},
|
|
337 {"void func(int x) { int v_array[^[[x]]][10]; }", "DeclRefExpr"},
|
|
338
|
|
339 {"int (*getFunc([[do^uble]]))(int);", "BuiltinTypeLoc"},
|
|
340
|
|
341 // Member pointers and pack expansion use declarator syntax, but are
|
|
342 // restricted so they don't need special casing.
|
|
343 {"class X{}; [[int X::^*]]y[10];", "MemberPointerTypeLoc"},
|
|
344 {"template<typename ...T> void foo([[T*^...]]x);",
|
|
345 "PackExpansionTypeLoc"},
|
|
346 {"template<typename ...T> void foo([[^T]]*...x);",
|
|
347 "TemplateTypeParmTypeLoc"},
|
|
348
|
150
|
349 // FIXME: the AST has no location info for qualifiers.
|
|
350 {"const [[a^uto]] x = 42;", "AutoTypeLoc"},
|
236
|
351 {"co^nst auto x = 42;", nullptr},
|
150
|
352
|
|
353 {"^", nullptr},
|
|
354 {"void foo() { [[foo^^]] (); }", "DeclRefExpr"},
|
|
355
|
|
356 // FIXME: Ideally we'd get a declstmt or the VarDecl itself here.
|
|
357 // This doesn't happen now; the RAV doesn't traverse a node containing ;.
|
|
358 {"int x = 42;^", nullptr},
|
|
359
|
|
360 // Common ancestor is logically TUDecl, but we never return that.
|
|
361 {"^int x; int y;^", nullptr},
|
|
362
|
|
363 // Node types that have caused problems in the past.
|
|
364 {"template <typename T> void foo() { [[^T]] t; }",
|
|
365 "TemplateTypeParmTypeLoc"},
|
|
366
|
|
367 // No crash
|
|
368 {
|
|
369 R"cpp(
|
|
370 template <class T> struct Foo {};
|
|
371 template <[[template<class> class /*cursor here*/^U]]>
|
|
372 struct Foo<U<int>*> {};
|
|
373 )cpp",
|
|
374 "TemplateTemplateParmDecl"},
|
|
375
|
|
376 // Foreach has a weird AST, ensure we can select parts of the range init.
|
|
377 // This used to fail, because the DeclStmt for C claimed the whole range.
|
|
378 {
|
|
379 R"cpp(
|
|
380 struct Str {
|
|
381 const char *begin();
|
|
382 const char *end();
|
|
383 };
|
|
384 Str makeStr(const char*);
|
|
385 void loop() {
|
|
386 for (const char C : [[mak^eStr("foo"^)]])
|
|
387 ;
|
|
388 }
|
|
389 )cpp",
|
|
390 "CallExpr"},
|
|
391
|
|
392 // User-defined literals are tricky: is 12_i one token or two?
|
|
393 // For now we treat it as one, and the UserDefinedLiteral as a leaf.
|
|
394 {
|
|
395 R"cpp(
|
|
396 struct Foo{};
|
|
397 Foo operator""_ud(unsigned long long);
|
|
398 Foo x = [[^12_ud]];
|
|
399 )cpp",
|
|
400 "UserDefinedLiteral"},
|
|
401
|
|
402 {
|
|
403 R"cpp(
|
|
404 int a;
|
|
405 decltype([[^a]] + a) b;
|
|
406 )cpp",
|
|
407 "DeclRefExpr"},
|
236
|
408 {"[[decltype^(1)]] b;", "DecltypeTypeLoc"}, // Not the VarDecl.
|
|
409 // decltype(auto) is an AutoTypeLoc!
|
|
410 {"[[de^cltype(a^uto)]] a = 1;", "AutoTypeLoc"},
|
150
|
411
|
221
|
412 // Objective-C nullability attributes.
|
|
413 {
|
|
414 R"cpp(
|
|
415 @interface I{}
|
|
416 @property(nullable) [[^I]] *x;
|
|
417 @end
|
|
418 )cpp",
|
|
419 "ObjCInterfaceTypeLoc"},
|
|
420 {
|
|
421 R"cpp(
|
|
422 @interface I{}
|
|
423 - (void)doSomething:(nonnull [[i^d]])argument;
|
|
424 @end
|
|
425 )cpp",
|
|
426 "TypedefTypeLoc"},
|
|
427
|
150
|
428 // Objective-C OpaqueValueExpr/PseudoObjectExpr has weird ASTs.
|
|
429 // Need to traverse the contents of the OpaqueValueExpr to the POE,
|
|
430 // and ensure we traverse only the syntactic form of the PseudoObjectExpr.
|
|
431 {
|
|
432 R"cpp(
|
|
433 @interface I{}
|
|
434 @property(retain) I*x;
|
|
435 @property(retain) I*y;
|
|
436 @end
|
|
437 void test(I *f) { [[^f]].x.y = 0; }
|
|
438 )cpp",
|
|
439 "DeclRefExpr"},
|
|
440 {
|
|
441 R"cpp(
|
|
442 @interface I{}
|
|
443 @property(retain) I*x;
|
|
444 @property(retain) I*y;
|
|
445 @end
|
|
446 void test(I *f) { [[f.^x]].y = 0; }
|
|
447 )cpp",
|
|
448 "ObjCPropertyRefExpr"},
|
|
449 // Examples with implicit properties.
|
|
450 {
|
|
451 R"cpp(
|
|
452 @interface I{}
|
|
453 -(int)foo;
|
|
454 @end
|
|
455 int test(I *f) { return 42 + [[^f]].foo; }
|
|
456 )cpp",
|
|
457 "DeclRefExpr"},
|
|
458 {
|
|
459 R"cpp(
|
|
460 @interface I{}
|
|
461 -(int)foo;
|
|
462 @end
|
|
463 int test(I *f) { return 42 + [[f.^foo]]; }
|
|
464 )cpp",
|
|
465 "ObjCPropertyRefExpr"},
|
173
|
466 {"struct foo { [[int has^h<:32:>]]; };", "FieldDecl"},
|
|
467 {"struct foo { [[op^erator int()]]; };", "CXXConversionDecl"},
|
|
468 {"struct foo { [[^~foo()]]; };", "CXXDestructorDecl"},
|
236
|
469 {"struct foo { [[~^foo()]]; };", "CXXDestructorDecl"},
|
|
470 {"template <class T> struct foo { ~foo<[[^T]]>(){} };",
|
|
471 "TemplateTypeParmTypeLoc"},
|
|
472 {"struct foo {}; void bar(foo *f) { [[f->~^foo]](); }", "MemberExpr"},
|
173
|
473 {"struct foo { [[fo^o(){}]] };", "CXXConstructorDecl"},
|
|
474
|
|
475 {R"cpp(
|
|
476 struct S1 { void f(); };
|
|
477 struct S2 { S1 * operator->(); };
|
|
478 void test(S2 s2) {
|
|
479 s2[[-^>]]f();
|
|
480 }
|
221
|
481 )cpp",
|
|
482 "DeclRefExpr"}, // DeclRefExpr to the "operator->" method.
|
|
483
|
|
484 // Template template argument.
|
|
485 {R"cpp(
|
|
486 template <typename> class Vector {};
|
|
487 template <template <typename> class Container> class A {};
|
|
488 A<[[V^ector]]> a;
|
|
489 )cpp",
|
236
|
490 "TemplateArgumentLoc"},
|
|
491
|
|
492 // Attributes
|
|
493 {R"cpp(
|
|
494 void f(int * __attribute__(([[no^nnull]])) );
|
|
495 )cpp",
|
|
496 "NonNullAttr"},
|
|
497
|
|
498 {R"cpp(
|
|
499 // Digraph syntax for attributes to avoid accidental annotations.
|
|
500 class <:[gsl::Owner([[in^t]])]:> X{};
|
|
501 )cpp",
|
|
502 "BuiltinTypeLoc"},
|
|
503
|
|
504 // This case used to crash - AST has a null Attr
|
|
505 {R"cpp(
|
|
506 @interface I
|
|
507 [[@property(retain, nonnull) <:[My^Object2]:> *x]]; // error-ok
|
|
508 @end
|
|
509 )cpp",
|
|
510 "ObjCPropertyDecl"},
|
|
511
|
|
512 {R"cpp(
|
|
513 typedef int Foo;
|
|
514 enum Bar : [[Fo^o]] {};
|
|
515 )cpp",
|
|
516 "TypedefTypeLoc"},
|
|
517 {R"cpp(
|
|
518 typedef int Foo;
|
|
519 enum Bar : [[Fo^o]];
|
|
520 )cpp",
|
|
521 "TypedefTypeLoc"},
|
|
522
|
|
523 // lambda captured var-decl
|
|
524 {R"cpp(
|
|
525 void test(int bar) {
|
|
526 auto l = [^[[foo = bar]]] { };
|
|
527 })cpp",
|
|
528 "VarDecl"},
|
|
529 {R"cpp(
|
|
530 /*error-ok*/
|
|
531 void func() [[{^]])cpp",
|
|
532 "CompoundStmt"},
|
|
533 {R"cpp(
|
|
534 void func() { [[__^func__]]; }
|
|
535 )cpp",
|
|
536 "PredefinedExpr"},
|
|
537
|
|
538 // using enum
|
|
539 {R"cpp(
|
|
540 namespace ns { enum class A {}; };
|
|
541 using enum ns::[[^A]];
|
|
542 )cpp",
|
|
543 "EnumTypeLoc"},
|
|
544 {R"cpp(
|
|
545 namespace ns { enum class A {}; using B = A; };
|
|
546 using enum ns::[[^B]];
|
|
547 )cpp",
|
|
548 "TypedefTypeLoc"},
|
|
549 {R"cpp(
|
|
550 namespace ns { enum class A {}; };
|
|
551 using enum [[^ns::]]A;
|
|
552 )cpp",
|
|
553 "NestedNameSpecifierLoc"},
|
|
554 {R"cpp(
|
|
555 namespace ns { enum class A {}; };
|
|
556 [[using ^enum ns::A]];
|
|
557 )cpp",
|
|
558 "UsingEnumDecl"},
|
|
559 {R"cpp(
|
|
560 namespace ns { enum class A {}; };
|
|
561 [[^using enum ns::A]];
|
|
562 )cpp",
|
|
563 "UsingEnumDecl"},
|
|
564 };
|
221
|
565
|
150
|
566 for (const Case &C : Cases) {
|
173
|
567 trace::TestTracer Tracer;
|
150
|
568 Annotations Test(C.Code);
|
|
569
|
|
570 TestTU TU;
|
|
571 TU.Code = std::string(Test.code());
|
|
572
|
|
573 TU.ExtraArgs.push_back("-xobjective-c++");
|
236
|
574 TU.ExtraArgs.push_back("-std=c++20");
|
150
|
575
|
|
576 auto AST = TU.build();
|
|
577 auto T = makeSelectionTree(C.Code, AST);
|
|
578 EXPECT_EQ("TranslationUnitDecl", nodeKind(&T.root())) << C.Code;
|
|
579
|
|
580 if (Test.ranges().empty()) {
|
|
581 // If no [[range]] is marked in the example, there should be no selection.
|
|
582 EXPECT_FALSE(T.commonAncestor()) << C.Code << "\n" << T;
|
221
|
583 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),
|
|
584 testing::IsEmpty());
|
150
|
585 } else {
|
|
586 // If there is an expected selection, common ancestor should exist
|
|
587 // with the appropriate node type.
|
|
588 EXPECT_EQ(C.CommonAncestorKind, nodeKind(T.commonAncestor()))
|
|
589 << C.Code << "\n"
|
|
590 << T;
|
|
591 // Convert the reported common ancestor to a range and verify it.
|
|
592 EXPECT_EQ(nodeRange(T.commonAncestor(), AST), Test.range())
|
|
593 << C.Code << "\n"
|
|
594 << T;
|
|
595
|
|
596 // Check that common ancestor is reachable on exactly one path from root,
|
|
597 // and no nodes outside it are selected.
|
|
598 EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code))
|
|
599 << C.Code;
|
221
|
600 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),
|
|
601 ElementsAreArray({0}));
|
150
|
602 }
|
|
603 }
|
|
604 }
|
|
605
|
|
606 // Regression test: this used to match the injected X, not the outer X.
|
|
607 TEST(SelectionTest, InjectedClassName) {
|
173
|
608 const char *Code = "struct ^X { int x; };";
|
150
|
609 auto AST = TestTU::withCode(Annotations(Code).code()).build();
|
|
610 auto T = makeSelectionTree(Code, AST);
|
|
611 ASSERT_EQ("CXXRecordDecl", nodeKind(T.commonAncestor())) << T;
|
|
612 auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<Decl>());
|
|
613 EXPECT_FALSE(D->isInjectedClassName());
|
|
614 }
|
|
615
|
173
|
616 TEST(SelectionTree, Metrics) {
|
|
617 const char *Code = R"cpp(
|
|
618 // error-ok: testing behavior on recovery expression
|
|
619 int foo();
|
|
620 int foo(int, int);
|
|
621 int x = fo^o(42);
|
|
622 )cpp";
|
|
623 auto AST = TestTU::withCode(Annotations(Code).code()).build();
|
|
624 trace::TestTracer Tracer;
|
|
625 auto T = makeSelectionTree(Code, AST);
|
221
|
626 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),
|
|
627 ElementsAreArray({1}));
|
|
628 EXPECT_THAT(Tracer.takeMetric("selection_recovery_type", "C++"),
|
|
629 ElementsAreArray({1}));
|
173
|
630 }
|
|
631
|
150
|
632 // FIXME: Doesn't select the binary operator node in
|
|
633 // #define FOO(X) X + 1
|
|
634 // int a, b = [[FOO(a)]];
|
|
635 TEST(SelectionTest, Selected) {
|
|
636 // Selection with ^marks^.
|
|
637 // Partially selected nodes marked with a [[range]].
|
|
638 // Completely selected nodes marked with a $C[[range]].
|
|
639 const char *Cases[] = {
|
|
640 R"cpp( int abc, xyz = [[^ab^c]]; )cpp",
|
|
641 R"cpp( int abc, xyz = [[a^bc^]]; )cpp",
|
|
642 R"cpp( int abc, xyz = $C[[^abc^]]; )cpp",
|
|
643 R"cpp(
|
|
644 void foo() {
|
|
645 [[if ([[1^11]]) $C[[{
|
|
646 $C[[return]];
|
|
647 }]] else [[{^
|
|
648 }]]]]
|
|
649 char z;
|
|
650 }
|
|
651 )cpp",
|
|
652 R"cpp(
|
|
653 template <class T>
|
|
654 struct unique_ptr {};
|
|
655 void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {}
|
|
656 )cpp",
|
|
657 R"cpp(int a = [[5 >^> 1]];)cpp",
|
|
658 R"cpp(
|
|
659 #define ECHO(X) X
|
|
660 ECHO(EC^HO($C[[int]]) EC^HO(a));
|
|
661 )cpp",
|
|
662 R"cpp( $C[[^$C[[int]] a^]]; )cpp",
|
|
663 R"cpp( $C[[^$C[[int]] a = $C[[5]]^]]; )cpp",
|
|
664 };
|
|
665 for (const char *C : Cases) {
|
|
666 Annotations Test(C);
|
|
667 auto AST = TestTU::withCode(Test.code()).build();
|
|
668 auto T = makeSelectionTree(C, AST);
|
|
669
|
|
670 std::vector<Range> Complete, Partial;
|
|
671 for (const SelectionTree::Node *N : allNodes(T))
|
|
672 if (N->Selected == SelectionTree::Complete)
|
|
673 Complete.push_back(nodeRange(N, AST));
|
|
674 else if (N->Selected == SelectionTree::Partial)
|
|
675 Partial.push_back(nodeRange(N, AST));
|
|
676 EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges("C"))) << C;
|
|
677 EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) << C;
|
|
678 }
|
|
679 }
|
|
680
|
|
681 TEST(SelectionTest, PathologicalPreprocessor) {
|
|
682 const char *Case = R"cpp(
|
|
683 #define MACRO while(1)
|
|
684 void test() {
|
|
685 #include "Expand.inc"
|
|
686 br^eak;
|
|
687 }
|
|
688 )cpp";
|
|
689 Annotations Test(Case);
|
|
690 auto TU = TestTU::withCode(Test.code());
|
|
691 TU.AdditionalFiles["Expand.inc"] = "MACRO\n";
|
|
692 auto AST = TU.build();
|
252
|
693 EXPECT_THAT(AST.getDiagnostics(), ::testing::IsEmpty());
|
150
|
694 auto T = makeSelectionTree(Case, AST);
|
|
695
|
|
696 EXPECT_EQ("BreakStmt", T.commonAncestor()->kind());
|
|
697 EXPECT_EQ("WhileStmt", T.commonAncestor()->Parent->kind());
|
|
698 }
|
|
699
|
|
700 TEST(SelectionTest, IncludedFile) {
|
|
701 const char *Case = R"cpp(
|
|
702 void test() {
|
|
703 #include "Exp^and.inc"
|
|
704 break;
|
|
705 }
|
|
706 )cpp";
|
|
707 Annotations Test(Case);
|
|
708 auto TU = TestTU::withCode(Test.code());
|
|
709 TU.AdditionalFiles["Expand.inc"] = "while(1)\n";
|
|
710 auto AST = TU.build();
|
|
711 auto T = makeSelectionTree(Case, AST);
|
|
712
|
221
|
713 EXPECT_EQ(nullptr, T.commonAncestor());
|
150
|
714 }
|
|
715
|
|
716 TEST(SelectionTest, MacroArgExpansion) {
|
173
|
717 // If a macro arg is expanded several times, we only consider the first one
|
|
718 // selected.
|
150
|
719 const char *Case = R"cpp(
|
|
720 int mul(int, int);
|
|
721 #define SQUARE(X) mul(X, X);
|
|
722 int nine = SQUARE(^3);
|
|
723 )cpp";
|
|
724 Annotations Test(Case);
|
|
725 auto AST = TestTU::withCode(Test.code()).build();
|
|
726 auto T = makeSelectionTree(Case, AST);
|
173
|
727 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
|
|
728 EXPECT_TRUE(T.commonAncestor()->Selected);
|
150
|
729
|
|
730 // Verify that the common assert() macro doesn't suffer from this.
|
|
731 // (This is because we don't associate the stringified token with the arg).
|
|
732 Case = R"cpp(
|
|
733 void die(const char*);
|
|
734 #define assert(x) (x ? (void)0 : die(#x))
|
|
735 void foo() { assert(^42); }
|
|
736 )cpp";
|
|
737 Test = Annotations(Case);
|
|
738 AST = TestTU::withCode(Test.code()).build();
|
|
739 T = makeSelectionTree(Case, AST);
|
236
|
740 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
|
150
|
741
|
236
|
742 // Reduced from private bug involving RETURN_IF_ERROR.
|
|
743 // Due to >>-splitting and a bug in isBeforeInTranslationUnit, the inner
|
|
744 // S<int> would claim way too many tokens.
|
|
745 Case = R"cpp(
|
|
746 #define ID(x) x
|
|
747 template <typename T> class S {};
|
|
748 ID(
|
|
749 ID(S<S<int>> x);
|
|
750 int ^y;
|
|
751 )
|
|
752 )cpp";
|
|
753 Test = Annotations(Case);
|
|
754 AST = TestTU::withCode(Test.code()).build();
|
|
755 T = makeSelectionTree(Case, AST);
|
|
756 // not TemplateSpecializationTypeLoc!
|
|
757 EXPECT_EQ("VarDecl", T.commonAncestor()->kind());
|
150
|
758 }
|
|
759
|
|
760 TEST(SelectionTest, Implicit) {
|
173
|
761 const char *Test = R"cpp(
|
150
|
762 struct S { S(const char*); };
|
|
763 int f(S);
|
|
764 int x = f("^");
|
|
765 )cpp";
|
236
|
766 auto TU = TestTU::withCode(Annotations(Test).code());
|
|
767 // C++14 AST contains some temporaries that C++17 elides.
|
|
768 TU.ExtraArgs.push_back("-std=c++17");
|
|
769 auto AST = TU.build();
|
150
|
770 auto T = makeSelectionTree(Test, AST);
|
|
771
|
|
772 const SelectionTree::Node *Str = T.commonAncestor();
|
|
773 EXPECT_EQ("StringLiteral", nodeKind(Str)) << "Implicit selected?";
|
|
774 EXPECT_EQ("ImplicitCastExpr", nodeKind(Str->Parent));
|
|
775 EXPECT_EQ("CXXConstructExpr", nodeKind(Str->Parent->Parent));
|
236
|
776 const SelectionTree::Node *ICE = Str->Parent->Parent->Parent;
|
|
777 EXPECT_EQ("ImplicitCastExpr", nodeKind(ICE));
|
|
778 EXPECT_EQ("CallExpr", nodeKind(ICE->Parent));
|
|
779 EXPECT_EQ(Str, &ICE->ignoreImplicit())
|
|
780 << "Didn't unwrap " << nodeKind(&ICE->ignoreImplicit());
|
150
|
781
|
236
|
782 EXPECT_EQ(ICE, &Str->outerImplicit());
|
150
|
783 }
|
|
784
|
173
|
785 TEST(SelectionTest, CreateAll) {
|
|
786 llvm::Annotations Test("int$unique^ a=1$ambiguous^+1; $empty^");
|
|
787 auto AST = TestTU::withCode(Test.code()).build();
|
|
788 unsigned Seen = 0;
|
|
789 SelectionTree::createEach(
|
|
790 AST.getASTContext(), AST.getTokens(), Test.point("ambiguous"),
|
|
791 Test.point("ambiguous"), [&](SelectionTree T) {
|
|
792 // Expect to see the right-biased tree first.
|
223
|
793 if (Seen == 0) {
|
173
|
794 EXPECT_EQ("BinaryOperator", nodeKind(T.commonAncestor()));
|
223
|
795 } else if (Seen == 1) {
|
173
|
796 EXPECT_EQ("IntegerLiteral", nodeKind(T.commonAncestor()));
|
223
|
797 }
|
173
|
798 ++Seen;
|
|
799 return false;
|
|
800 });
|
|
801 EXPECT_EQ(2u, Seen);
|
|
802
|
|
803 Seen = 0;
|
|
804 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
|
|
805 Test.point("ambiguous"), Test.point("ambiguous"),
|
|
806 [&](SelectionTree T) {
|
|
807 ++Seen;
|
|
808 return true;
|
|
809 });
|
|
810 EXPECT_EQ(1u, Seen) << "Return true --> stop iterating";
|
|
811
|
|
812 Seen = 0;
|
|
813 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
|
|
814 Test.point("unique"), Test.point("unique"),
|
|
815 [&](SelectionTree T) {
|
|
816 ++Seen;
|
|
817 return false;
|
|
818 });
|
|
819 EXPECT_EQ(1u, Seen) << "no ambiguity --> only one tree";
|
|
820
|
|
821 Seen = 0;
|
|
822 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
|
|
823 Test.point("empty"), Test.point("empty"),
|
|
824 [&](SelectionTree T) {
|
|
825 EXPECT_FALSE(T.commonAncestor());
|
|
826 ++Seen;
|
|
827 return false;
|
|
828 });
|
|
829 EXPECT_EQ(1u, Seen) << "empty tree still created";
|
|
830
|
|
831 Seen = 0;
|
|
832 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
|
|
833 Test.point("unique"), Test.point("ambiguous"),
|
|
834 [&](SelectionTree T) {
|
|
835 ++Seen;
|
|
836 return false;
|
|
837 });
|
|
838 EXPECT_EQ(1u, Seen) << "one tree for nontrivial selection";
|
|
839 }
|
|
840
|
236
|
841 TEST(SelectionTest, DeclContextIsLexical) {
|
|
842 llvm::Annotations Test("namespace a { void $1^foo(); } void a::$2^foo();");
|
|
843 auto AST = TestTU::withCode(Test.code()).build();
|
|
844 {
|
|
845 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
|
|
846 Test.point("1"), Test.point("1"));
|
|
847 EXPECT_FALSE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
|
|
848 }
|
|
849 {
|
|
850 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
|
|
851 Test.point("2"), Test.point("2"));
|
|
852 EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
|
|
853 }
|
|
854 }
|
|
855
|
150
|
856 } // namespace
|
|
857 } // namespace clangd
|
|
858 } // namespace clang
|