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 "support/TestTracer.h"
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 {
21 using ::testing::UnorderedElementsAreArray;
22
23 // Create a selection tree corresponding to a point or pair of points.
24 // This uses the precisely-defined createRight semantics. The fuzzier
25 // createEach is tested separately.
makeSelectionTree(const StringRef MarkedCode,ParsedAST & AST)26 SelectionTree makeSelectionTree(const StringRef MarkedCode, ParsedAST &AST) {
27 Annotations Test(MarkedCode);
28 switch (Test.points().size()) {
29 case 1: { // Point selection.
30 unsigned Offset = cantFail(positionToOffset(Test.code(), Test.point()));
31 return SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
32 Offset, Offset);
33 }
34 case 2: // Range selection.
35 return SelectionTree::createRight(
36 AST.getASTContext(), AST.getTokens(),
37 cantFail(positionToOffset(Test.code(), Test.points()[0])),
38 cantFail(positionToOffset(Test.code(), Test.points()[1])));
39 default:
40 ADD_FAILURE() << "Expected 1-2 points for selection.\n" << MarkedCode;
41 return SelectionTree::createRight(AST.getASTContext(), AST.getTokens(), 0u,
42 0u);
43 }
44 }
45
nodeRange(const SelectionTree::Node * N,ParsedAST & AST)46 Range nodeRange(const SelectionTree::Node *N, ParsedAST &AST) {
47 if (!N)
48 return Range{};
49 const SourceManager &SM = AST.getSourceManager();
50 const LangOptions &LangOpts = AST.getLangOpts();
51 StringRef Buffer = SM.getBufferData(SM.getMainFileID());
52 if (llvm::isa_and_nonnull<TranslationUnitDecl>(N->ASTNode.get<Decl>()))
53 return Range{Position{}, offsetToPosition(Buffer, Buffer.size())};
54 auto FileRange =
55 toHalfOpenFileRange(SM, LangOpts, N->ASTNode.getSourceRange());
56 assert(FileRange && "We should be able to get the File Range");
57 return Range{
58 offsetToPosition(Buffer, SM.getFileOffset(FileRange->getBegin())),
59 offsetToPosition(Buffer, SM.getFileOffset(FileRange->getEnd()))};
60 }
61
nodeKind(const SelectionTree::Node * N)62 std::string nodeKind(const SelectionTree::Node *N) {
63 return N ? N->kind() : "<null>";
64 }
65
allNodes(const SelectionTree & T)66 std::vector<const SelectionTree::Node *> allNodes(const SelectionTree &T) {
67 std::vector<const SelectionTree::Node *> Result = {&T.root()};
68 for (unsigned I = 0; I < Result.size(); ++I) {
69 const SelectionTree::Node *N = Result[I];
70 Result.insert(Result.end(), N->Children.begin(), N->Children.end());
71 }
72 return Result;
73 }
74
75 // Returns true if Common is a descendent of Root.
76 // Verifies nothing is selected above Common.
verifyCommonAncestor(const SelectionTree::Node & Root,const SelectionTree::Node * Common,StringRef MarkedCode)77 bool verifyCommonAncestor(const SelectionTree::Node &Root,
78 const SelectionTree::Node *Common,
79 StringRef MarkedCode) {
80 if (&Root == Common)
81 return true;
82 if (Root.Selected)
83 ADD_FAILURE() << "Selected nodes outside common ancestor\n" << MarkedCode;
84 bool Seen = false;
85 for (const SelectionTree::Node *Child : Root.Children)
86 if (verifyCommonAncestor(*Child, Common, MarkedCode)) {
87 if (Seen)
88 ADD_FAILURE() << "Saw common ancestor twice\n" << MarkedCode;
89 Seen = true;
90 }
91 return Seen;
92 }
93
TEST(SelectionTest,CommonAncestor)94 TEST(SelectionTest, CommonAncestor) {
95 struct Case {
96 // Selection is between ^marks^.
97 // common ancestor marked with a [[range]].
98 const char *Code;
99 const char *CommonAncestorKind;
100 };
101 Case Cases[] = {
102 {
103 R"cpp(
104 template <typename T>
105 int x = [[T::^U::]]ccc();
106 )cpp",
107 "NestedNameSpecifierLoc",
108 },
109 {
110 R"cpp(
111 struct AAA { struct BBB { static int ccc(); };};
112 int x = AAA::[[B^B^B]]::ccc();
113 )cpp",
114 "RecordTypeLoc",
115 },
116 {
117 R"cpp(
118 struct AAA { struct BBB { static int ccc(); };};
119 int x = AAA::[[B^BB^]]::ccc();
120 )cpp",
121 "RecordTypeLoc",
122 },
123 {
124 R"cpp(
125 struct AAA { struct BBB { static int ccc(); };};
126 int x = [[AAA::BBB::c^c^c]]();
127 )cpp",
128 "DeclRefExpr",
129 },
130 {
131 R"cpp(
132 struct AAA { struct BBB { static int ccc(); };};
133 int x = [[AAA::BBB::cc^c(^)]];
134 )cpp",
135 "CallExpr",
136 },
137
138 {
139 R"cpp(
140 void foo() { [[if (1^11) { return; } else {^ }]] }
141 )cpp",
142 "IfStmt",
143 },
144 {
145 R"cpp(
146 int x(int);
147 #define M(foo) x(foo)
148 int a = 42;
149 int b = M([[^a]]);
150 )cpp",
151 "DeclRefExpr",
152 },
153 {
154 R"cpp(
155 void foo();
156 #define CALL_FUNCTION(X) X()
157 void bar() { CALL_FUNCTION([[f^o^o]]); }
158 )cpp",
159 "DeclRefExpr",
160 },
161 {
162 R"cpp(
163 void foo();
164 #define CALL_FUNCTION(X) X()
165 void bar() { [[CALL_FUNC^TION(fo^o)]]; }
166 )cpp",
167 "CallExpr",
168 },
169 {
170 R"cpp(
171 void foo();
172 #define CALL_FUNCTION(X) X()
173 void bar() { [[C^ALL_FUNC^TION(foo)]]; }
174 )cpp",
175 "CallExpr",
176 },
177 {
178 R"cpp(
179 void foo();
180 #define CALL_FUNCTION(X) X^()^
181 void bar() { CALL_FUNCTION(foo); }
182 )cpp",
183 nullptr,
184 },
185 {
186 R"cpp(
187 struct S { S(const char*); };
188 S [[s ^= "foo"]];
189 )cpp",
190 "CXXConstructExpr",
191 },
192 {
193 R"cpp(
194 struct S { S(const char*); };
195 [[S ^s = "foo"]];
196 )cpp",
197 "VarDecl",
198 },
199 {
200 R"cpp(
201 [[^void]] (*S)(int) = nullptr;
202 )cpp",
203 "BuiltinTypeLoc",
204 },
205 {
206 R"cpp(
207 [[void (*S)^(int)]] = nullptr;
208 )cpp",
209 "FunctionProtoTypeLoc",
210 },
211 {
212 R"cpp(
213 [[void (^*S)(int)]] = nullptr;
214 )cpp",
215 "FunctionProtoTypeLoc",
216 },
217 {
218 R"cpp(
219 [[void (*^S)(int) = nullptr]];
220 )cpp",
221 "VarDecl",
222 },
223 {
224 R"cpp(
225 [[void ^(*S)(int)]] = nullptr;
226 )cpp",
227 "FunctionProtoTypeLoc",
228 },
229 {
230 R"cpp(
231 struct S {
232 int foo() const;
233 int bar() { return [[f^oo]](); }
234 };
235 )cpp",
236 "MemberExpr", // Not implicit CXXThisExpr, or its implicit cast!
237 },
238 {
239 R"cpp(
240 auto lambda = [](const char*){ return 0; };
241 int x = lambda([["y^"]]);
242 )cpp",
243 "StringLiteral", // Not DeclRefExpr to operator()!
244 },
245
246 // Point selections.
247 {"void foo() { [[^foo]](); }", "DeclRefExpr"},
248 {"void foo() { [[f^oo]](); }", "DeclRefExpr"},
249 {"void foo() { [[fo^o]](); }", "DeclRefExpr"},
250 {"void foo() { [[foo^()]]; }", "CallExpr"},
251 {"void foo() { [[foo^]] (); }", "DeclRefExpr"},
252 {"int bar; void foo() [[{ foo (); }]]^", "CompoundStmt"},
253 {"int x = [[42]]^;", "IntegerLiteral"},
254
255 // Ignores whitespace, comments, and semicolons in the selection.
256 {"void foo() { [[foo^()]]; /*comment*/^}", "CallExpr"},
257
258 // Tricky case: FunctionTypeLoc in FunctionDecl has a hole in it.
259 {"[[^void]] foo();", "BuiltinTypeLoc"},
260 {"[[void foo^()]];", "FunctionProtoTypeLoc"},
261 {"[[^void foo^()]];", "FunctionDecl"},
262 {"[[void ^foo()]];", "FunctionDecl"},
263 // Tricky case: two VarDecls share a specifier.
264 {"[[int ^a]], b;", "VarDecl"},
265 {"[[int a, ^b]];", "VarDecl"},
266 // Tricky case: CXXConstructExpr wants to claim the whole init range.
267 {
268 R"cpp(
269 struct X { X(int); };
270 class Y {
271 X x;
272 Y() : [[^x(4)]] {}
273 };
274 )cpp",
275 "CXXCtorInitializer", // Not the CXXConstructExpr!
276 },
277 // Tricky case: anonymous struct is a sibling of the VarDecl.
278 {"[[st^ruct {int x;}]] y;", "CXXRecordDecl"},
279 {"[[struct {int x;} ^y]];", "VarDecl"},
280 {"struct {[[int ^x]];} y;", "FieldDecl"},
281 // FIXME: the AST has no location info for qualifiers.
282 {"const [[a^uto]] x = 42;", "AutoTypeLoc"},
283 {"[[co^nst auto x = 42]];", "VarDecl"},
284
285 {"^", nullptr},
286 {"void foo() { [[foo^^]] (); }", "DeclRefExpr"},
287
288 // FIXME: Ideally we'd get a declstmt or the VarDecl itself here.
289 // This doesn't happen now; the RAV doesn't traverse a node containing ;.
290 {"int x = 42;^", nullptr},
291
292 // Common ancestor is logically TUDecl, but we never return that.
293 {"^int x; int y;^", nullptr},
294
295 // Node types that have caused problems in the past.
296 {"template <typename T> void foo() { [[^T]] t; }",
297 "TemplateTypeParmTypeLoc"},
298
299 // No crash
300 {
301 R"cpp(
302 template <class T> struct Foo {};
303 template <[[template<class> class /*cursor here*/^U]]>
304 struct Foo<U<int>*> {};
305 )cpp",
306 "TemplateTemplateParmDecl"},
307
308 // Foreach has a weird AST, ensure we can select parts of the range init.
309 // This used to fail, because the DeclStmt for C claimed the whole range.
310 {
311 R"cpp(
312 struct Str {
313 const char *begin();
314 const char *end();
315 };
316 Str makeStr(const char*);
317 void loop() {
318 for (const char C : [[mak^eStr("foo"^)]])
319 ;
320 }
321 )cpp",
322 "CallExpr"},
323
324 // User-defined literals are tricky: is 12_i one token or two?
325 // For now we treat it as one, and the UserDefinedLiteral as a leaf.
326 {
327 R"cpp(
328 struct Foo{};
329 Foo operator""_ud(unsigned long long);
330 Foo x = [[^12_ud]];
331 )cpp",
332 "UserDefinedLiteral"},
333
334 {
335 R"cpp(
336 int a;
337 decltype([[^a]] + a) b;
338 )cpp",
339 "DeclRefExpr"},
340
341 // Objective-C OpaqueValueExpr/PseudoObjectExpr has weird ASTs.
342 // Need to traverse the contents of the OpaqueValueExpr to the POE,
343 // and ensure we traverse only the syntactic form of the PseudoObjectExpr.
344 {
345 R"cpp(
346 @interface I{}
347 @property(retain) I*x;
348 @property(retain) I*y;
349 @end
350 void test(I *f) { [[^f]].x.y = 0; }
351 )cpp",
352 "DeclRefExpr"},
353 {
354 R"cpp(
355 @interface I{}
356 @property(retain) I*x;
357 @property(retain) I*y;
358 @end
359 void test(I *f) { [[f.^x]].y = 0; }
360 )cpp",
361 "ObjCPropertyRefExpr"},
362 // Examples with implicit properties.
363 {
364 R"cpp(
365 @interface I{}
366 -(int)foo;
367 @end
368 int test(I *f) { return 42 + [[^f]].foo; }
369 )cpp",
370 "DeclRefExpr"},
371 {
372 R"cpp(
373 @interface I{}
374 -(int)foo;
375 @end
376 int test(I *f) { return 42 + [[f.^foo]]; }
377 )cpp",
378 "ObjCPropertyRefExpr"},
379 {"struct foo { [[int has^h<:32:>]]; };", "FieldDecl"},
380 {"struct foo { [[op^erator int()]]; };", "CXXConversionDecl"},
381 {"struct foo { [[^~foo()]]; };", "CXXDestructorDecl"},
382 // FIXME: The following to should be class itself instead.
383 {"struct foo { [[fo^o(){}]] };", "CXXConstructorDecl"},
384
385 {R"cpp(
386 struct S1 { void f(); };
387 struct S2 { S1 * operator->(); };
388 void test(S2 s2) {
389 s2[[-^>]]f();
390 }
391 )cpp", "DeclRefExpr"} // DeclRefExpr to the "operator->" method.
392 };
393 for (const Case &C : Cases) {
394 trace::TestTracer Tracer;
395 Annotations Test(C.Code);
396
397 TestTU TU;
398 TU.Code = std::string(Test.code());
399
400 // FIXME: Auto-completion in a template requires disabling delayed template
401 // parsing.
402 TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
403 TU.ExtraArgs.push_back("-xobjective-c++");
404
405 auto AST = TU.build();
406 auto T = makeSelectionTree(C.Code, AST);
407 EXPECT_EQ("TranslationUnitDecl", nodeKind(&T.root())) << C.Code;
408
409 if (Test.ranges().empty()) {
410 // If no [[range]] is marked in the example, there should be no selection.
411 EXPECT_FALSE(T.commonAncestor()) << C.Code << "\n" << T;
412 EXPECT_THAT(Tracer.takeMetric("selection_recovery"), testing::IsEmpty());
413 } else {
414 // If there is an expected selection, common ancestor should exist
415 // with the appropriate node type.
416 EXPECT_EQ(C.CommonAncestorKind, nodeKind(T.commonAncestor()))
417 << C.Code << "\n"
418 << T;
419 // Convert the reported common ancestor to a range and verify it.
420 EXPECT_EQ(nodeRange(T.commonAncestor(), AST), Test.range())
421 << C.Code << "\n"
422 << T;
423
424 // Check that common ancestor is reachable on exactly one path from root,
425 // and no nodes outside it are selected.
426 EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code))
427 << C.Code;
428 EXPECT_THAT(Tracer.takeMetric("selection_recovery"),
429 testing::ElementsAreArray({0}));
430 }
431 }
432 }
433
434 // Regression test: this used to match the injected X, not the outer X.
TEST(SelectionTest,InjectedClassName)435 TEST(SelectionTest, InjectedClassName) {
436 const char *Code = "struct ^X { int x; };";
437 auto AST = TestTU::withCode(Annotations(Code).code()).build();
438 auto T = makeSelectionTree(Code, AST);
439 ASSERT_EQ("CXXRecordDecl", nodeKind(T.commonAncestor())) << T;
440 auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<Decl>());
441 EXPECT_FALSE(D->isInjectedClassName());
442 }
443
TEST(SelectionTree,Metrics)444 TEST(SelectionTree, Metrics) {
445 const char *Code = R"cpp(
446 // error-ok: testing behavior on recovery expression
447 int foo();
448 int foo(int, int);
449 int x = fo^o(42);
450 )cpp";
451 auto AST = TestTU::withCode(Annotations(Code).code()).build();
452 trace::TestTracer Tracer;
453 auto T = makeSelectionTree(Code, AST);
454 EXPECT_THAT(Tracer.takeMetric("selection_recovery"),
455 testing::ElementsAreArray({1}));
456 EXPECT_THAT(Tracer.takeMetric("selection_recovery_type"),
457 testing::ElementsAreArray({1}));
458 }
459
460 // FIXME: Doesn't select the binary operator node in
461 // #define FOO(X) X + 1
462 // int a, b = [[FOO(a)]];
TEST(SelectionTest,Selected)463 TEST(SelectionTest, Selected) {
464 // Selection with ^marks^.
465 // Partially selected nodes marked with a [[range]].
466 // Completely selected nodes marked with a $C[[range]].
467 const char *Cases[] = {
468 R"cpp( int abc, xyz = [[^ab^c]]; )cpp",
469 R"cpp( int abc, xyz = [[a^bc^]]; )cpp",
470 R"cpp( int abc, xyz = $C[[^abc^]]; )cpp",
471 R"cpp(
472 void foo() {
473 [[if ([[1^11]]) $C[[{
474 $C[[return]];
475 }]] else [[{^
476 }]]]]
477 char z;
478 }
479 )cpp",
480 R"cpp(
481 template <class T>
482 struct unique_ptr {};
483 void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {}
484 )cpp",
485 R"cpp(int a = [[5 >^> 1]];)cpp",
486 R"cpp(
487 #define ECHO(X) X
488 ECHO(EC^HO($C[[int]]) EC^HO(a));
489 )cpp",
490 R"cpp( $C[[^$C[[int]] a^]]; )cpp",
491 R"cpp( $C[[^$C[[int]] a = $C[[5]]^]]; )cpp",
492 };
493 for (const char *C : Cases) {
494 Annotations Test(C);
495 auto AST = TestTU::withCode(Test.code()).build();
496 auto T = makeSelectionTree(C, AST);
497
498 std::vector<Range> Complete, Partial;
499 for (const SelectionTree::Node *N : allNodes(T))
500 if (N->Selected == SelectionTree::Complete)
501 Complete.push_back(nodeRange(N, AST));
502 else if (N->Selected == SelectionTree::Partial)
503 Partial.push_back(nodeRange(N, AST));
504 EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges("C"))) << C;
505 EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) << C;
506 }
507 }
508
TEST(SelectionTest,PathologicalPreprocessor)509 TEST(SelectionTest, PathologicalPreprocessor) {
510 const char *Case = R"cpp(
511 #define MACRO while(1)
512 void test() {
513 #include "Expand.inc"
514 br^eak;
515 }
516 )cpp";
517 Annotations Test(Case);
518 auto TU = TestTU::withCode(Test.code());
519 TU.AdditionalFiles["Expand.inc"] = "MACRO\n";
520 auto AST = TU.build();
521 EXPECT_THAT(AST.getDiagnostics(), ::testing::IsEmpty());
522 auto T = makeSelectionTree(Case, AST);
523
524 EXPECT_EQ("BreakStmt", T.commonAncestor()->kind());
525 EXPECT_EQ("WhileStmt", T.commonAncestor()->Parent->kind());
526 }
527
TEST(SelectionTest,IncludedFile)528 TEST(SelectionTest, IncludedFile) {
529 const char *Case = R"cpp(
530 void test() {
531 #include "Exp^and.inc"
532 break;
533 }
534 )cpp";
535 Annotations Test(Case);
536 auto TU = TestTU::withCode(Test.code());
537 TU.AdditionalFiles["Expand.inc"] = "while(1)\n";
538 auto AST = TU.build();
539 auto T = makeSelectionTree(Case, AST);
540
541 EXPECT_EQ("WhileStmt", T.commonAncestor()->kind());
542 }
543
TEST(SelectionTest,MacroArgExpansion)544 TEST(SelectionTest, MacroArgExpansion) {
545 // If a macro arg is expanded several times, we only consider the first one
546 // selected.
547 const char *Case = R"cpp(
548 int mul(int, int);
549 #define SQUARE(X) mul(X, X);
550 int nine = SQUARE(^3);
551 )cpp";
552 Annotations Test(Case);
553 auto AST = TestTU::withCode(Test.code()).build();
554 auto T = makeSelectionTree(Case, AST);
555 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
556 EXPECT_TRUE(T.commonAncestor()->Selected);
557
558 // Verify that the common assert() macro doesn't suffer from this.
559 // (This is because we don't associate the stringified token with the arg).
560 Case = R"cpp(
561 void die(const char*);
562 #define assert(x) (x ? (void)0 : die(#x))
563 void foo() { assert(^42); }
564 )cpp";
565 Test = Annotations(Case);
566 AST = TestTU::withCode(Test.code()).build();
567 T = makeSelectionTree(Case, AST);
568
569 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
570 }
571
TEST(SelectionTest,Implicit)572 TEST(SelectionTest, Implicit) {
573 const char *Test = R"cpp(
574 struct S { S(const char*); };
575 int f(S);
576 int x = f("^");
577 )cpp";
578 auto AST = TestTU::withCode(Annotations(Test).code()).build();
579 auto T = makeSelectionTree(Test, AST);
580
581 const SelectionTree::Node *Str = T.commonAncestor();
582 EXPECT_EQ("StringLiteral", nodeKind(Str)) << "Implicit selected?";
583 EXPECT_EQ("ImplicitCastExpr", nodeKind(Str->Parent));
584 EXPECT_EQ("CXXConstructExpr", nodeKind(Str->Parent->Parent));
585 EXPECT_EQ(Str, &Str->Parent->Parent->ignoreImplicit())
586 << "Didn't unwrap " << nodeKind(&Str->Parent->Parent->ignoreImplicit());
587
588 EXPECT_EQ("CXXConstructExpr", nodeKind(&Str->outerImplicit()));
589 }
590
TEST(SelectionTest,CreateAll)591 TEST(SelectionTest, CreateAll) {
592 llvm::Annotations Test("int$unique^ a=1$ambiguous^+1; $empty^");
593 auto AST = TestTU::withCode(Test.code()).build();
594 unsigned Seen = 0;
595 SelectionTree::createEach(
596 AST.getASTContext(), AST.getTokens(), Test.point("ambiguous"),
597 Test.point("ambiguous"), [&](SelectionTree T) {
598 // Expect to see the right-biased tree first.
599 if (Seen == 0)
600 EXPECT_EQ("BinaryOperator", nodeKind(T.commonAncestor()));
601 else if (Seen == 1)
602 EXPECT_EQ("IntegerLiteral", nodeKind(T.commonAncestor()));
603 ++Seen;
604 return false;
605 });
606 EXPECT_EQ(2u, Seen);
607
608 Seen = 0;
609 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
610 Test.point("ambiguous"), Test.point("ambiguous"),
611 [&](SelectionTree T) {
612 ++Seen;
613 return true;
614 });
615 EXPECT_EQ(1u, Seen) << "Return true --> stop iterating";
616
617 Seen = 0;
618 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
619 Test.point("unique"), Test.point("unique"),
620 [&](SelectionTree T) {
621 ++Seen;
622 return false;
623 });
624 EXPECT_EQ(1u, Seen) << "no ambiguity --> only one tree";
625
626 Seen = 0;
627 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
628 Test.point("empty"), Test.point("empty"),
629 [&](SelectionTree T) {
630 EXPECT_FALSE(T.commonAncestor());
631 ++Seen;
632 return false;
633 });
634 EXPECT_EQ(1u, Seen) << "empty tree still created";
635
636 Seen = 0;
637 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
638 Test.point("unique"), Test.point("ambiguous"),
639 [&](SelectionTree T) {
640 ++Seen;
641 return false;
642 });
643 EXPECT_EQ(1u, Seen) << "one tree for nontrivial selection";
644 }
645
646 } // namespace
647 } // namespace clangd
648 } // namespace clang
649