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