clang-tools 19.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/Decl.h"
14#include "llvm/Support/Casting.h"
15#include "gmock/gmock.h"
16#include "gtest/gtest.h"
17
18namespace clang {
19namespace clangd {
20namespace {
21using ::testing::ElementsAreArray;
22using ::testing::UnorderedElementsAreArray;
23
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.
27SelectionTree makeSelectionTree(const StringRef MarkedCode, ParsedAST &AST) {
28 Annotations Test(MarkedCode);
29 switch (Test.points().size()) {
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 }
35 case 2: // Range selection.
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;
42 return SelectionTree::createRight(AST.getASTContext(), AST.getTokens(), 0u,
43 0u);
44 }
45}
46
47Range 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
63std::string nodeKind(const SelectionTree::Node *N) {
64 return N ? N->kind() : "<null>";
65}
66
67std::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.
78bool 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
95TEST(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();
181 #^define CALL_FUNCTION(X) X(^)
182 void bar() { CALL_FUNCTION(foo); }
183 )cpp",
184 nullptr,
185 },
186 {
187 R"cpp(
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(
206 #define TARGET void foo()
207 [[TAR^GET{ return; }]]
208 )cpp",
209 "FunctionDecl",
210 },
211 {
212 R"cpp(
213 struct S { S(const char*); };
214 [[S s ^= "foo"]];
215 )cpp",
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",
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",
244 "PointerTypeLoc",
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",
256 "ParenTypeLoc",
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 },
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 },
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"},
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
349 // FIXME: the AST has no location info for qualifiers.
350 {"const [[a^uto]] x = 42;", "AutoTypeLoc"},
351 {"co^nst auto x = 42;", nullptr},
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"},
408 {"[[decltype^(1)]] b;", "DecltypeTypeLoc"}, // Not the VarDecl.
409 // decltype(auto) is an AutoTypeLoc!
410 {"[[de^cltype(a^uto)]] a = 1;", "AutoTypeLoc"},
411
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
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"},
466 {"struct foo { [[int has^h<:32:>]]; };", "FieldDecl"},
467 {"struct foo { [[op^erator int()]]; };", "CXXConversionDecl"},
468 {"struct foo { [[^~foo()]]; };", "CXXDestructorDecl"},
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"},
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 }
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",
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
565 // concepts
566 {R"cpp(
567 template <class> concept C = true;
568 auto x = [[^C<int>]];
569 )cpp",
570 "ConceptReference"},
571 {R"cpp(
572 template <class> concept C = true;
573 [[^C]] auto x = 0;
574 )cpp",
575 "ConceptReference"},
576 {R"cpp(
577 template <class> concept C = true;
578 void foo([[^C]] auto x) {}
579 )cpp",
580 "ConceptReference"},
581 {R"cpp(
582 template <class> concept C = true;
583 template <[[^C]] x> int i = 0;
584 )cpp",
585 "ConceptReference"},
586 {R"cpp(
587 namespace ns { template <class> concept C = true; }
588 auto x = [[ns::^C<int>]];
589 )cpp",
590 "ConceptReference"},
591 };
592
593 for (const Case &C : Cases) {
594 trace::TestTracer Tracer;
595 Annotations Test(C.Code);
596
597 TestTU TU;
598 TU.Code = std::string(Test.code());
599
600 TU.ExtraArgs.push_back("-xobjective-c++");
601 TU.ExtraArgs.push_back("-std=c++20");
602
603 auto AST = TU.build();
604 auto T = makeSelectionTree(C.Code, AST);
605 EXPECT_EQ("TranslationUnitDecl", nodeKind(&T.root())) << C.Code;
606
607 if (Test.ranges().empty()) {
608 // If no [[range]] is marked in the example, there should be no selection.
609 EXPECT_FALSE(T.commonAncestor()) << C.Code << "\n" << T;
610 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),
611 testing::IsEmpty());
612 } else {
613 // If there is an expected selection, common ancestor should exist
614 // with the appropriate node type.
615 EXPECT_EQ(C.CommonAncestorKind, nodeKind(T.commonAncestor()))
616 << C.Code << "\n"
617 << T;
618 // Convert the reported common ancestor to a range and verify it.
619 EXPECT_EQ(nodeRange(T.commonAncestor(), AST), Test.range())
620 << C.Code << "\n"
621 << T;
622
623 // Check that common ancestor is reachable on exactly one path from root,
624 // and no nodes outside it are selected.
625 EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code))
626 << C.Code;
627 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),
628 ElementsAreArray({0}));
629 }
630 }
631}
632
633// Regression test: this used to match the injected X, not the outer X.
634TEST(SelectionTest, InjectedClassName) {
635 const char *Code = "struct ^X { int x; };";
636 auto AST = TestTU::withCode(Annotations(Code).code()).build();
637 auto T = makeSelectionTree(Code, AST);
638 ASSERT_EQ("CXXRecordDecl", nodeKind(T.commonAncestor())) << T;
639 auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<Decl>());
640 EXPECT_FALSE(D->isInjectedClassName());
641}
642
643TEST(SelectionTree, Metrics) {
644 const char *Code = R"cpp(
645 // error-ok: testing behavior on recovery expression
646 int foo();
647 int foo(int, int);
648 int x = fo^o(42);
649 )cpp";
650 auto AST = TestTU::withCode(Annotations(Code).code()).build();
651 trace::TestTracer Tracer;
652 auto T = makeSelectionTree(Code, AST);
653 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),
654 ElementsAreArray({1}));
655 EXPECT_THAT(Tracer.takeMetric("selection_recovery_type", "C++"),
656 ElementsAreArray({1}));
657}
658
659// FIXME: Doesn't select the binary operator node in
660// #define FOO(X) X + 1
661// int a, b = [[FOO(a)]];
662TEST(SelectionTest, Selected) {
663 // Selection with ^marks^.
664 // Partially selected nodes marked with a [[range]].
665 // Completely selected nodes marked with a $C[[range]].
666 const char *Cases[] = {
667 R"cpp( int abc, xyz = [[^ab^c]]; )cpp",
668 R"cpp( int abc, xyz = [[a^bc^]]; )cpp",
669 R"cpp( int abc, xyz = $C[[^abc^]]; )cpp",
670 R"cpp(
671 void foo() {
672 [[if ([[1^11]]) $C[[{
673 $C[[return]];
674 }]] else [[{^
675 }]]]]
676 char z;
677 }
678 )cpp",
679 R"cpp(
680 template <class T>
681 struct unique_ptr {};
682 void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {}
683 )cpp",
684 R"cpp(int a = [[5 >^> 1]];)cpp",
685 R"cpp(
686 #define ECHO(X) X
687 ECHO(EC^HO($C[[int]]) EC^HO(a));
688 )cpp",
689 R"cpp( $C[[^$C[[int]] a^]]; )cpp",
690 R"cpp( $C[[^$C[[int]] a = $C[[5]]^]]; )cpp",
691 };
692 for (const char *C : Cases) {
693 Annotations Test(C);
694 auto AST = TestTU::withCode(Test.code()).build();
695 auto T = makeSelectionTree(C, AST);
696
697 std::vector<Range> Complete, Partial;
698 for (const SelectionTree::Node *N : allNodes(T))
699 if (N->Selected == SelectionTree::Complete)
700 Complete.push_back(nodeRange(N, AST));
701 else if (N->Selected == SelectionTree::Partial)
702 Partial.push_back(nodeRange(N, AST));
703 EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges("C"))) << C;
704 EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) << C;
705 }
706}
707
708TEST(SelectionTest, PathologicalPreprocessor) {
709 const char *Case = R"cpp(
710#define MACRO while(1)
711 void test() {
712#include "Expand.inc"
713 br^eak;
714 }
715 )cpp";
716 Annotations Test(Case);
717 auto TU = TestTU::withCode(Test.code());
718 TU.AdditionalFiles["Expand.inc"] = "MACRO\n";
719 auto AST = TU.build();
720 EXPECT_THAT(AST.getDiagnostics(), ::testing::IsEmpty());
721 auto T = makeSelectionTree(Case, AST);
722
723 EXPECT_EQ("BreakStmt", T.commonAncestor()->kind());
724 EXPECT_EQ("WhileStmt", T.commonAncestor()->Parent->kind());
725}
726
727TEST(SelectionTest, IncludedFile) {
728 const char *Case = R"cpp(
729 void test() {
730#include "Exp^and.inc"
731 break;
732 }
733 )cpp";
734 Annotations Test(Case);
735 auto TU = TestTU::withCode(Test.code());
736 TU.AdditionalFiles["Expand.inc"] = "while(1)\n";
737 auto AST = TU.build();
738 auto T = makeSelectionTree(Case, AST);
739
740 EXPECT_EQ(nullptr, T.commonAncestor());
741}
742
743TEST(SelectionTest, MacroArgExpansion) {
744 // If a macro arg is expanded several times, we only consider the first one
745 // selected.
746 const char *Case = R"cpp(
747 int mul(int, int);
748 #define SQUARE(X) mul(X, X);
749 int nine = SQUARE(^3);
750 )cpp";
751 Annotations Test(Case);
752 auto AST = TestTU::withCode(Test.code()).build();
753 auto T = makeSelectionTree(Case, AST);
754 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
755 EXPECT_TRUE(T.commonAncestor()->Selected);
756
757 // Verify that the common assert() macro doesn't suffer from this.
758 // (This is because we don't associate the stringified token with the arg).
759 Case = R"cpp(
760 void die(const char*);
761 #define assert(x) (x ? (void)0 : die(#x))
762 void foo() { assert(^42); }
763 )cpp";
764 Test = Annotations(Case);
765 AST = TestTU::withCode(Test.code()).build();
766 T = makeSelectionTree(Case, AST);
767 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
768
769 // Reduced from private bug involving RETURN_IF_ERROR.
770 // Due to >>-splitting and a bug in isBeforeInTranslationUnit, the inner
771 // S<int> would claim way too many tokens.
772 Case = R"cpp(
773 #define ID(x) x
774 template <typename T> class S {};
775 ID(
776 ID(S<S<int>> x);
777 int ^y;
778 )
779 )cpp";
780 Test = Annotations(Case);
781 AST = TestTU::withCode(Test.code()).build();
782 T = makeSelectionTree(Case, AST);
783 // not TemplateSpecializationTypeLoc!
784 EXPECT_EQ("VarDecl", T.commonAncestor()->kind());
785}
786
787TEST(SelectionTest, Implicit) {
788 const char *Test = R"cpp(
789 struct S { S(const char*); };
790 int f(S);
791 int x = f("^");
792 )cpp";
793 auto TU = TestTU::withCode(Annotations(Test).code());
794 // C++14 AST contains some temporaries that C++17 elides.
795 TU.ExtraArgs.push_back("-std=c++17");
796 auto AST = TU.build();
797 auto T = makeSelectionTree(Test, AST);
798
799 const SelectionTree::Node *Str = T.commonAncestor();
800 EXPECT_EQ("StringLiteral", nodeKind(Str)) << "Implicit selected?";
801 EXPECT_EQ("ImplicitCastExpr", nodeKind(Str->Parent));
802 EXPECT_EQ("CXXConstructExpr", nodeKind(Str->Parent->Parent));
803 const SelectionTree::Node *ICE = Str->Parent->Parent->Parent;
804 EXPECT_EQ("ImplicitCastExpr", nodeKind(ICE));
805 EXPECT_EQ("CallExpr", nodeKind(ICE->Parent));
806 EXPECT_EQ(Str, &ICE->ignoreImplicit())
807 << "Didn't unwrap " << nodeKind(&ICE->ignoreImplicit());
808
809 EXPECT_EQ(ICE, &Str->outerImplicit());
810}
811
812TEST(SelectionTest, CreateAll) {
813 llvm::Annotations Test("int$unique^ a=1$ambiguous^+1; $empty^");
814 auto AST = TestTU::withCode(Test.code()).build();
815 unsigned Seen = 0;
817 AST.getASTContext(), AST.getTokens(), Test.point("ambiguous"),
818 Test.point("ambiguous"), [&](SelectionTree T) {
819 // Expect to see the right-biased tree first.
820 if (Seen == 0) {
821 EXPECT_EQ("BinaryOperator", nodeKind(T.commonAncestor()));
822 } else if (Seen == 1) {
823 EXPECT_EQ("IntegerLiteral", nodeKind(T.commonAncestor()));
824 }
825 ++Seen;
826 return false;
827 });
828 EXPECT_EQ(2u, Seen);
829
830 Seen = 0;
831 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
832 Test.point("ambiguous"), Test.point("ambiguous"),
833 [&](SelectionTree T) {
834 ++Seen;
835 return true;
836 });
837 EXPECT_EQ(1u, Seen) << "Return true --> stop iterating";
838
839 Seen = 0;
840 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
841 Test.point("unique"), Test.point("unique"),
842 [&](SelectionTree T) {
843 ++Seen;
844 return false;
845 });
846 EXPECT_EQ(1u, Seen) << "no ambiguity --> only one tree";
847
848 Seen = 0;
849 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
850 Test.point("empty"), Test.point("empty"),
851 [&](SelectionTree T) {
852 EXPECT_FALSE(T.commonAncestor());
853 ++Seen;
854 return false;
855 });
856 EXPECT_EQ(1u, Seen) << "empty tree still created";
857
858 Seen = 0;
859 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),
860 Test.point("unique"), Test.point("ambiguous"),
861 [&](SelectionTree T) {
862 ++Seen;
863 return false;
864 });
865 EXPECT_EQ(1u, Seen) << "one tree for nontrivial selection";
866}
867
868TEST(SelectionTest, DeclContextIsLexical) {
869 llvm::Annotations Test("namespace a { void $1^foo(); } void a::$2^foo();");
870 auto AST = TestTU::withCode(Test.code()).build();
871 {
872 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
873 Test.point("1"), Test.point("1"));
874 EXPECT_FALSE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
875 }
876 {
877 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
878 Test.point("2"), Test.point("2"));
879 EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
880 }
881}
882
883TEST(SelectionTest, DeclContextLambda) {
884 llvm::Annotations Test(R"cpp(
885 void foo();
886 auto lambda = [] {
887 return $1^foo();
888 };
889 )cpp");
890 auto AST = TestTU::withCode(Test.code()).build();
891 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
892 Test.point("1"), Test.point("1"));
893 EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isFunctionOrMethod());
894}
895
896} // namespace
897} // namespace clangd
898} // namespace clang
const FunctionDecl * Decl
size_t Offset
ASTNode Root
Definition: DumpAST.cpp:342
std::string Code
const Criteria C
CharSourceRange Range
SourceRange for the file name.
SelectionTree::Selection Selected
Definition: Selection.cpp:534
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
Definition: Selection.cpp:1055
static SelectionTree createRight(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End)
Definition: Selection.cpp:1067
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.
Definition: SourceCode.cpp:430
Position offsetToPosition(llvm::StringRef Code, size_t Offset)
Turn an offset in Code into a [line, column] pair.
Definition: SourceCode.cpp:202
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:173
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
ParsedAST build() const
Definition: TestTU.cpp:114
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:36