[SCCP] Avoid modifying AdditionalUsers while iterating over it
[llvm-project.git] / clang / unittests / Tooling / ASTSelectionTest.cpp
blob88988ef4478753e6c95f925ca9cc9ad882588553
1 //===- unittest/Tooling/ASTSelectionTest.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 //===----------------------------------------------------------------------===//
9 #include "TestVisitor.h"
10 #include "clang/Basic/SourceManager.h"
11 #include "clang/Tooling/Refactoring/ASTSelection.h"
13 using namespace clang;
14 using namespace tooling;
16 namespace {
18 struct FileLocation {
19 unsigned Line, Column;
21 SourceLocation translate(const SourceManager &SM) {
22 return SM.translateLineCol(SM.getMainFileID(), Line, Column);
26 using FileRange = std::pair<FileLocation, FileLocation>;
28 class SelectionFinderVisitor : public TestVisitor<SelectionFinderVisitor> {
29 FileLocation Location;
30 Optional<FileRange> SelectionRange;
31 llvm::function_ref<void(SourceRange SelectionRange,
32 Optional<SelectedASTNode>)>
33 Consumer;
35 public:
36 SelectionFinderVisitor(FileLocation Location,
37 Optional<FileRange> SelectionRange,
38 llvm::function_ref<void(SourceRange SelectionRange,
39 Optional<SelectedASTNode>)>
40 Consumer)
41 : Location(Location), SelectionRange(SelectionRange), Consumer(Consumer) {
44 bool VisitTranslationUnitDecl(const TranslationUnitDecl *TU) {
45 const ASTContext &Context = TU->getASTContext();
46 const SourceManager &SM = Context.getSourceManager();
48 SourceRange SelRange;
49 if (SelectionRange) {
50 SelRange = SourceRange(SelectionRange->first.translate(SM),
51 SelectionRange->second.translate(SM));
52 } else {
53 SourceLocation Loc = Location.translate(SM);
54 SelRange = SourceRange(Loc, Loc);
56 Consumer(SelRange, findSelectedASTNodes(Context, SelRange));
57 return false;
61 /// This is a test utility function that computes the AST selection at the
62 /// given location with an optional selection range.
63 ///
64 /// A location roughly corresponds to a cursor location in an editor, while
65 /// the optional range corresponds to the selection range in an editor.
66 void findSelectedASTNodesWithRange(
67 StringRef Source, FileLocation Location, Optional<FileRange> SelectionRange,
68 llvm::function_ref<void(SourceRange SelectionRange,
69 Optional<SelectedASTNode>)>
70 Consumer,
71 SelectionFinderVisitor::Language Language =
72 SelectionFinderVisitor::Lang_CXX11) {
73 SelectionFinderVisitor Visitor(Location, SelectionRange, Consumer);
74 EXPECT_TRUE(Visitor.runOver(Source, Language));
77 void findSelectedASTNodes(
78 StringRef Source, FileLocation Location, Optional<FileRange> SelectionRange,
79 llvm::function_ref<void(Optional<SelectedASTNode>)> Consumer,
80 SelectionFinderVisitor::Language Language =
81 SelectionFinderVisitor::Lang_CXX11) {
82 findSelectedASTNodesWithRange(
83 Source, Location, SelectionRange,
84 [&](SourceRange, Optional<SelectedASTNode> Selection) {
85 Consumer(std::move(Selection));
87 Language);
90 void checkNodeImpl(bool IsTypeMatched, const SelectedASTNode &Node,
91 SourceSelectionKind SelectionKind, unsigned NumChildren) {
92 ASSERT_TRUE(IsTypeMatched);
93 EXPECT_EQ(Node.Children.size(), NumChildren);
94 ASSERT_EQ(Node.SelectionKind, SelectionKind);
97 void checkDeclName(const SelectedASTNode &Node, StringRef Name) {
98 const auto *ND = Node.Node.get<NamedDecl>();
99 EXPECT_TRUE(!!ND);
100 ASSERT_EQ(ND->getName(), Name);
103 template <typename T>
104 const SelectedASTNode &checkNode(
105 const SelectedASTNode &StmtNode, SourceSelectionKind SelectionKind,
106 unsigned NumChildren = 0,
107 std::enable_if_t<std::is_base_of<Stmt, T>::value, T> *StmtOverloadChecker =
108 nullptr) {
109 checkNodeImpl(isa<T>(StmtNode.Node.get<Stmt>()), StmtNode, SelectionKind,
110 NumChildren);
111 return StmtNode;
114 template <typename T>
115 const SelectedASTNode &checkNode(
116 const SelectedASTNode &DeclNode, SourceSelectionKind SelectionKind,
117 unsigned NumChildren = 0, StringRef Name = "",
118 std::enable_if_t<std::is_base_of<Decl, T>::value, T> *DeclOverloadChecker =
119 nullptr) {
120 checkNodeImpl(isa<T>(DeclNode.Node.get<Decl>()), DeclNode, SelectionKind,
121 NumChildren);
122 if (!Name.empty())
123 checkDeclName(DeclNode, Name);
124 return DeclNode;
127 struct ForAllChildrenOf {
128 const SelectedASTNode &Node;
130 static void childKindVerifier(const SelectedASTNode &Node,
131 SourceSelectionKind SelectionKind) {
132 for (const SelectedASTNode &Child : Node.Children) {
133 ASSERT_EQ(Node.SelectionKind, SelectionKind);
134 childKindVerifier(Child, SelectionKind);
138 public:
139 ForAllChildrenOf(const SelectedASTNode &Node) : Node(Node) {}
141 void shouldHaveSelectionKind(SourceSelectionKind Kind) {
142 childKindVerifier(Node, Kind);
146 ForAllChildrenOf allChildrenOf(const SelectedASTNode &Node) {
147 return ForAllChildrenOf(Node);
150 TEST(ASTSelectionFinder, CursorNoSelection) {
151 findSelectedASTNodes(
152 " void f() { }", {1, 1}, None,
153 [](Optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
156 TEST(ASTSelectionFinder, CursorAtStartOfFunction) {
157 findSelectedASTNodes(
158 "void f() { }", {1, 1}, None, [](Optional<SelectedASTNode> Node) {
159 EXPECT_TRUE(Node);
160 checkNode<TranslationUnitDecl>(*Node, SourceSelectionKind::None,
161 /*NumChildren=*/1);
162 checkNode<FunctionDecl>(Node->Children[0],
163 SourceSelectionKind::ContainsSelection,
164 /*NumChildren=*/0, /*Name=*/"f");
166 // Check that the dumping works.
167 std::string DumpValue;
168 llvm::raw_string_ostream OS(DumpValue);
169 Node->Children[0].dump(OS);
170 ASSERT_EQ(OS.str(), "FunctionDecl \"f\" contains-selection\n");
174 TEST(ASTSelectionFinder, RangeNoSelection) {
175 findSelectedASTNodes(
176 " void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
177 [](Optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
178 findSelectedASTNodes(
179 " void f() { }", {1, 1}, FileRange{{1, 1}, {1, 2}},
180 [](Optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
183 TEST(ASTSelectionFinder, EmptyRangeFallbackToCursor) {
184 findSelectedASTNodes("void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
185 [](Optional<SelectedASTNode> Node) {
186 EXPECT_TRUE(Node);
187 checkNode<FunctionDecl>(
188 Node->Children[0],
189 SourceSelectionKind::ContainsSelection,
190 /*NumChildren=*/0, /*Name=*/"f");
194 TEST(ASTSelectionFinder, WholeFunctionSelection) {
195 StringRef Source = "int f(int x) { return x;\n}\nvoid f2() { }";
196 // From 'int' until just after '}':
198 findSelectedASTNodes(
199 Source, {1, 1}, FileRange{{1, 1}, {2, 2}},
200 [](Optional<SelectedASTNode> Node) {
201 EXPECT_TRUE(Node);
202 EXPECT_EQ(Node->Children.size(), 1u);
203 const auto &Fn = checkNode<FunctionDecl>(
204 Node->Children[0], SourceSelectionKind::ContainsSelection,
205 /*NumChildren=*/2, /*Name=*/"f");
206 checkNode<ParmVarDecl>(Fn.Children[0],
207 SourceSelectionKind::InsideSelection);
208 const auto &Body = checkNode<CompoundStmt>(
209 Fn.Children[1], SourceSelectionKind::InsideSelection,
210 /*NumChildren=*/1);
211 const auto &Return = checkNode<ReturnStmt>(
212 Body.Children[0], SourceSelectionKind::InsideSelection,
213 /*NumChildren=*/1);
214 checkNode<ImplicitCastExpr>(Return.Children[0],
215 SourceSelectionKind::InsideSelection,
216 /*NumChildren=*/1);
217 checkNode<DeclRefExpr>(Return.Children[0].Children[0],
218 SourceSelectionKind::InsideSelection);
221 // From 'int' until just before '}':
222 findSelectedASTNodes(
223 Source, {2, 1}, FileRange{{1, 1}, {2, 1}},
224 [](Optional<SelectedASTNode> Node) {
225 EXPECT_TRUE(Node);
226 EXPECT_EQ(Node->Children.size(), 1u);
227 const auto &Fn = checkNode<FunctionDecl>(
228 Node->Children[0], SourceSelectionKind::ContainsSelection,
229 /*NumChildren=*/2, /*Name=*/"f");
230 const auto &Body = checkNode<CompoundStmt>(
231 Fn.Children[1], SourceSelectionKind::ContainsSelectionEnd,
232 /*NumChildren=*/1);
233 checkNode<ReturnStmt>(Body.Children[0],
234 SourceSelectionKind::InsideSelection,
235 /*NumChildren=*/1);
237 // From '{' until just after '}':
238 findSelectedASTNodes(
239 Source, {1, 14}, FileRange{{1, 14}, {2, 2}},
240 [](Optional<SelectedASTNode> Node) {
241 EXPECT_TRUE(Node);
242 EXPECT_EQ(Node->Children.size(), 1u);
243 const auto &Fn = checkNode<FunctionDecl>(
244 Node->Children[0], SourceSelectionKind::ContainsSelection,
245 /*NumChildren=*/1, /*Name=*/"f");
246 const auto &Body = checkNode<CompoundStmt>(
247 Fn.Children[0], SourceSelectionKind::ContainsSelection,
248 /*NumChildren=*/1);
249 checkNode<ReturnStmt>(Body.Children[0],
250 SourceSelectionKind::InsideSelection,
251 /*NumChildren=*/1);
253 // From 'x' until just after '}':
254 findSelectedASTNodes(
255 Source, {2, 2}, FileRange{{1, 11}, {2, 2}},
256 [](Optional<SelectedASTNode> Node) {
257 EXPECT_TRUE(Node);
258 EXPECT_EQ(Node->Children.size(), 1u);
259 const auto &Fn = checkNode<FunctionDecl>(
260 Node->Children[0], SourceSelectionKind::ContainsSelection,
261 /*NumChildren=*/2, /*Name=*/"f");
262 checkNode<ParmVarDecl>(Fn.Children[0],
263 SourceSelectionKind::ContainsSelectionStart);
264 const auto &Body = checkNode<CompoundStmt>(
265 Fn.Children[1], SourceSelectionKind::InsideSelection,
266 /*NumChildren=*/1);
267 checkNode<ReturnStmt>(Body.Children[0],
268 SourceSelectionKind::InsideSelection,
269 /*NumChildren=*/1);
273 TEST(ASTSelectionFinder, MultipleFunctionSelection) {
274 StringRef Source = R"(void f0() {
276 void f1() { }
277 void f2() { }
278 void f3() { }
280 auto SelectedF1F2 = [](Optional<SelectedASTNode> Node) {
281 EXPECT_TRUE(Node);
282 EXPECT_EQ(Node->Children.size(), 2u);
283 checkNode<FunctionDecl>(Node->Children[0],
284 SourceSelectionKind::InsideSelection,
285 /*NumChildren=*/1, /*Name=*/"f1");
286 checkNode<FunctionDecl>(Node->Children[1],
287 SourceSelectionKind::InsideSelection,
288 /*NumChildren=*/1, /*Name=*/"f2");
290 // Just after '}' of f0 and just before 'void' of f3:
291 findSelectedASTNodes(Source, {2, 2}, FileRange{{2, 2}, {5, 1}}, SelectedF1F2);
292 // Just before 'void' of f1 and just after '}' of f2:
293 findSelectedASTNodes(Source, {3, 1}, FileRange{{3, 1}, {4, 14}},
294 SelectedF1F2);
297 TEST(ASTSelectionFinder, MultipleStatementSelection) {
298 StringRef Source = R"(void f(int x, int y) {
299 int z = x;
300 f(2, 3);
301 if (x == 0) {
302 return;
304 x = 1;
305 return;
306 })";
307 // From 'f(2,3)' until just before 'x = 1;':
308 findSelectedASTNodes(
309 Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
310 [](Optional<SelectedASTNode> Node) {
311 EXPECT_TRUE(Node);
312 EXPECT_EQ(Node->Children.size(), 1u);
313 const auto &Fn = checkNode<FunctionDecl>(
314 Node->Children[0], SourceSelectionKind::ContainsSelection,
315 /*NumChildren=*/1, /*Name=*/"f");
316 const auto &Body = checkNode<CompoundStmt>(
317 Fn.Children[0], SourceSelectionKind::ContainsSelection,
318 /*NumChildren=*/2);
319 allChildrenOf(checkNode<CallExpr>(Body.Children[0],
320 SourceSelectionKind::InsideSelection,
321 /*NumChildren=*/3))
322 .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
323 allChildrenOf(checkNode<IfStmt>(Body.Children[1],
324 SourceSelectionKind::InsideSelection,
325 /*NumChildren=*/2))
326 .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
328 // From 'f(2,3)' until just before ';' in 'x = 1;':
329 findSelectedASTNodes(
330 Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
331 [](Optional<SelectedASTNode> Node) {
332 EXPECT_TRUE(Node);
333 EXPECT_EQ(Node->Children.size(), 1u);
334 const auto &Fn = checkNode<FunctionDecl>(
335 Node->Children[0], SourceSelectionKind::ContainsSelection,
336 /*NumChildren=*/1, /*Name=*/"f");
337 const auto &Body = checkNode<CompoundStmt>(
338 Fn.Children[0], SourceSelectionKind::ContainsSelection,
339 /*NumChildren=*/3);
340 checkNode<CallExpr>(Body.Children[0],
341 SourceSelectionKind::InsideSelection,
342 /*NumChildren=*/3);
343 checkNode<IfStmt>(Body.Children[1],
344 SourceSelectionKind::InsideSelection,
345 /*NumChildren=*/2);
346 checkNode<BinaryOperator>(Body.Children[2],
347 SourceSelectionKind::InsideSelection,
348 /*NumChildren=*/2);
350 // From the middle of 'int z = 3' until the middle of 'x = 1;':
351 findSelectedASTNodes(
352 Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
353 [](Optional<SelectedASTNode> Node) {
354 EXPECT_TRUE(Node);
355 EXPECT_EQ(Node->Children.size(), 1u);
356 const auto &Fn = checkNode<FunctionDecl>(
357 Node->Children[0], SourceSelectionKind::ContainsSelection,
358 /*NumChildren=*/1, /*Name=*/"f");
359 const auto &Body = checkNode<CompoundStmt>(
360 Fn.Children[0], SourceSelectionKind::ContainsSelection,
361 /*NumChildren=*/4);
362 checkNode<DeclStmt>(Body.Children[0],
363 SourceSelectionKind::ContainsSelectionStart,
364 /*NumChildren=*/1);
365 checkNode<CallExpr>(Body.Children[1],
366 SourceSelectionKind::InsideSelection,
367 /*NumChildren=*/3);
368 checkNode<IfStmt>(Body.Children[2],
369 SourceSelectionKind::InsideSelection,
370 /*NumChildren=*/2);
371 checkNode<BinaryOperator>(Body.Children[3],
372 SourceSelectionKind::ContainsSelectionEnd,
373 /*NumChildren=*/1);
377 TEST(ASTSelectionFinder, SelectionInFunctionInObjCImplementation) {
378 StringRef Source = R"(
379 @interface I
380 @end
381 @implementation I
383 int notSelected() { }
385 int selected(int x) {
386 return x;
389 @end
390 @implementation I(Cat)
392 void catF() { }
394 @end
396 void outerFunction() { }
398 // Just the 'x' expression in 'selected':
399 findSelectedASTNodes(
400 Source, {9, 10}, FileRange{{9, 10}, {9, 11}},
401 [](Optional<SelectedASTNode> Node) {
402 EXPECT_TRUE(Node);
403 EXPECT_EQ(Node->Children.size(), 1u);
404 const auto &Impl = checkNode<ObjCImplementationDecl>(
405 Node->Children[0], SourceSelectionKind::ContainsSelection,
406 /*NumChildren=*/1, /*Name=*/"I");
407 const auto &Fn = checkNode<FunctionDecl>(
408 Impl.Children[0], SourceSelectionKind::ContainsSelection,
409 /*NumChildren=*/1, /*Name=*/"selected");
410 allChildrenOf(Fn).shouldHaveSelectionKind(
411 SourceSelectionKind::ContainsSelection);
413 SelectionFinderVisitor::Lang_OBJC);
414 // The entire 'catF':
415 findSelectedASTNodes(
416 Source, {15, 1}, FileRange{{15, 1}, {15, 16}},
417 [](Optional<SelectedASTNode> Node) {
418 EXPECT_TRUE(Node);
419 EXPECT_EQ(Node->Children.size(), 1u);
420 const auto &Impl = checkNode<ObjCCategoryImplDecl>(
421 Node->Children[0], SourceSelectionKind::ContainsSelection,
422 /*NumChildren=*/1, /*Name=*/"Cat");
423 const auto &Fn = checkNode<FunctionDecl>(
424 Impl.Children[0], SourceSelectionKind::ContainsSelection,
425 /*NumChildren=*/1, /*Name=*/"catF");
426 allChildrenOf(Fn).shouldHaveSelectionKind(
427 SourceSelectionKind::ContainsSelection);
429 SelectionFinderVisitor::Lang_OBJC);
430 // From the line before 'selected' to the line after 'catF':
431 findSelectedASTNodes(
432 Source, {16, 1}, FileRange{{7, 1}, {16, 1}},
433 [](Optional<SelectedASTNode> Node) {
434 EXPECT_TRUE(Node);
435 EXPECT_EQ(Node->Children.size(), 2u);
436 const auto &Impl = checkNode<ObjCImplementationDecl>(
437 Node->Children[0], SourceSelectionKind::ContainsSelectionStart,
438 /*NumChildren=*/1, /*Name=*/"I");
439 const auto &Selected = checkNode<FunctionDecl>(
440 Impl.Children[0], SourceSelectionKind::InsideSelection,
441 /*NumChildren=*/2, /*Name=*/"selected");
442 allChildrenOf(Selected).shouldHaveSelectionKind(
443 SourceSelectionKind::InsideSelection);
444 const auto &Cat = checkNode<ObjCCategoryImplDecl>(
445 Node->Children[1], SourceSelectionKind::ContainsSelectionEnd,
446 /*NumChildren=*/1, /*Name=*/"Cat");
447 const auto &CatF = checkNode<FunctionDecl>(
448 Cat.Children[0], SourceSelectionKind::InsideSelection,
449 /*NumChildren=*/1, /*Name=*/"catF");
450 allChildrenOf(CatF).shouldHaveSelectionKind(
451 SourceSelectionKind::InsideSelection);
453 SelectionFinderVisitor::Lang_OBJC);
454 // Just the 'outer' function:
455 findSelectedASTNodes(Source, {19, 1}, FileRange{{19, 1}, {19, 25}},
456 [](Optional<SelectedASTNode> Node) {
457 EXPECT_TRUE(Node);
458 EXPECT_EQ(Node->Children.size(), 1u);
459 checkNode<FunctionDecl>(
460 Node->Children[0],
461 SourceSelectionKind::ContainsSelection,
462 /*NumChildren=*/1, /*Name=*/"outerFunction");
464 SelectionFinderVisitor::Lang_OBJC);
467 TEST(ASTSelectionFinder, FunctionInObjCImplementationCarefulWithEarlyExit) {
468 StringRef Source = R"(
469 @interface I
470 @end
471 @implementation I
473 void selected() {
476 - (void) method { }
478 @end
480 // Just 'selected'
481 findSelectedASTNodes(
482 Source, {6, 1}, FileRange{{6, 1}, {7, 2}},
483 [](Optional<SelectedASTNode> Node) {
484 EXPECT_TRUE(Node);
485 EXPECT_EQ(Node->Children.size(), 1u);
486 const auto &Impl = checkNode<ObjCImplementationDecl>(
487 Node->Children[0], SourceSelectionKind::ContainsSelection,
488 /*NumChildren=*/1, /*Name=*/"I");
489 checkNode<FunctionDecl>(Impl.Children[0],
490 SourceSelectionKind::ContainsSelection,
491 /*NumChildren=*/1, /*Name=*/"selected");
493 SelectionFinderVisitor::Lang_OBJC);
496 TEST(ASTSelectionFinder, AvoidImplicitDeclarations) {
497 StringRef Source = R"(
498 struct Copy {
499 int x;
501 void foo() {
502 Copy x;
503 Copy y = x;
506 // The entire struct 'Copy':
507 findSelectedASTNodes(
508 Source, {2, 1}, FileRange{{2, 1}, {4, 3}},
509 [](Optional<SelectedASTNode> Node) {
510 EXPECT_TRUE(Node);
511 EXPECT_EQ(Node->Children.size(), 1u);
512 const auto &Record = checkNode<CXXRecordDecl>(
513 Node->Children[0], SourceSelectionKind::InsideSelection,
514 /*NumChildren=*/1, /*Name=*/"Copy");
515 checkNode<FieldDecl>(Record.Children[0],
516 SourceSelectionKind::InsideSelection);
520 TEST(ASTSelectionFinder, CorrectEndForObjectiveCImplementation) {
521 StringRef Source = R"(
522 @interface I
523 @end
524 @implementation I
525 @ end
527 // Just after '@ end'
528 findSelectedASTNodes(Source, {5, 6}, None,
529 [](Optional<SelectedASTNode> Node) {
530 EXPECT_TRUE(Node);
531 EXPECT_EQ(Node->Children.size(), 1u);
532 checkNode<ObjCImplementationDecl>(
533 Node->Children[0],
534 SourceSelectionKind::ContainsSelection);
536 SelectionFinderVisitor::Lang_OBJC);
539 const SelectedASTNode &checkFnBody(const Optional<SelectedASTNode> &Node,
540 StringRef Name) {
541 EXPECT_TRUE(Node);
542 EXPECT_EQ(Node->Children.size(), 1u);
543 const auto &Fn = checkNode<FunctionDecl>(
544 Node->Children[0], SourceSelectionKind::ContainsSelection,
545 /*NumChildren=*/1, Name);
546 return checkNode<CompoundStmt>(Fn.Children[0],
547 SourceSelectionKind::ContainsSelection,
548 /*NumChildren=*/1);
551 TEST(ASTSelectionFinder, SelectObjectiveCPseudoObjectExprs) {
552 StringRef Source = R"(
553 @interface I
554 @property(readwrite) int prop;
555 @end
556 void selectProp(I *i) {
557 (void)i.prop;
558 i.prop = 21;
562 @interface NSMutableArray
563 - (id)objectAtIndexedSubscript:(unsigned int)index;
564 - (void)setObject:(id)object atIndexedSubscript:(unsigned int)index;
565 @end
567 void selectSubscript(NSMutableArray *array, I *i) {
568 (void)array[10];
569 array[i.prop] = i;
572 // Just 'i.prop'.
573 findSelectedASTNodes(
574 Source, {6, 7}, FileRange{{6, 7}, {6, 13}},
575 [](Optional<SelectedASTNode> Node) {
576 const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
577 const auto &CCast = checkNode<CStyleCastExpr>(
578 CS.Children[0], SourceSelectionKind::ContainsSelection,
579 /*NumChildren=*/1);
580 const auto &POE = checkNode<PseudoObjectExpr>(
581 CCast.Children[0], SourceSelectionKind::ContainsSelection,
582 /*NumChildren=*/1);
583 const auto &PRE = checkNode<ObjCPropertyRefExpr>(
584 POE.Children[0], SourceSelectionKind::ContainsSelection,
585 /*NumChildren=*/1);
586 const auto &Cast = checkNode<ImplicitCastExpr>(
587 PRE.Children[0], SourceSelectionKind::InsideSelection,
588 /*NumChildren=*/1);
589 checkNode<DeclRefExpr>(Cast.Children[0],
590 SourceSelectionKind::InsideSelection);
592 SelectionFinderVisitor::Lang_OBJC);
593 // Just 'i.prop = 21'
594 findSelectedASTNodes(
595 Source, {7, 1}, FileRange{{7, 1}, {7, 12}},
596 [](Optional<SelectedASTNode> Node) {
597 const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
598 const auto &POE = checkNode<PseudoObjectExpr>(
599 CS.Children[0], SourceSelectionKind::ContainsSelection,
600 /*NumChildren=*/1);
601 const auto &BinOp = checkNode<BinaryOperator>(
602 POE.Children[0], SourceSelectionKind::ContainsSelection,
603 /*NumChildren=*/2);
604 const auto &PRE = checkNode<ObjCPropertyRefExpr>(
605 BinOp.Children[0], SourceSelectionKind::InsideSelection,
606 /*NumChildren=*/1);
607 const auto &Cast = checkNode<ImplicitCastExpr>(
608 PRE.Children[0], SourceSelectionKind::InsideSelection,
609 /*NumChildren=*/1);
610 checkNode<DeclRefExpr>(Cast.Children[0],
611 SourceSelectionKind::InsideSelection);
612 checkNode<IntegerLiteral>(BinOp.Children[1],
613 SourceSelectionKind::InsideSelection);
615 SelectionFinderVisitor::Lang_OBJC);
616 // Just 'array[10]'
617 findSelectedASTNodes(
618 Source, {17, 9}, FileRange{{17, 9}, {17, 18}},
619 [](Optional<SelectedASTNode> Node) {
620 const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
621 const auto &CCast = checkNode<CStyleCastExpr>(
622 CS.Children[0], SourceSelectionKind::ContainsSelection,
623 /*NumChildren=*/1);
624 const auto &POE = checkNode<PseudoObjectExpr>(
625 CCast.Children[0], SourceSelectionKind::ContainsSelection,
626 /*NumChildren=*/1);
627 const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
628 POE.Children[0], SourceSelectionKind::ContainsSelection,
629 /*NumChildren=*/2);
630 const auto &Cast = checkNode<ImplicitCastExpr>(
631 SRE.Children[0], SourceSelectionKind::InsideSelection,
632 /*NumChildren=*/1);
633 checkNode<DeclRefExpr>(Cast.Children[0],
634 SourceSelectionKind::InsideSelection);
635 checkNode<IntegerLiteral>(SRE.Children[1],
636 SourceSelectionKind::InsideSelection);
638 SelectionFinderVisitor::Lang_OBJC);
639 // Just 'array[i.prop] = array'
640 findSelectedASTNodes(
641 Source, {18, 3}, FileRange{{18, 3}, {18, 20}},
642 [](Optional<SelectedASTNode> Node) {
643 const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
644 const auto &POE = checkNode<PseudoObjectExpr>(
645 CS.Children[0], SourceSelectionKind::ContainsSelection,
646 /*NumChildren=*/1);
647 const auto &BinOp = checkNode<BinaryOperator>(
648 POE.Children[0], SourceSelectionKind::ContainsSelection,
649 /*NumChildren=*/2);
650 const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
651 BinOp.Children[0], SourceSelectionKind::InsideSelection,
652 /*NumChildren=*/2);
653 const auto &Cast = checkNode<ImplicitCastExpr>(
654 SRE.Children[0], SourceSelectionKind::InsideSelection,
655 /*NumChildren=*/1);
656 checkNode<DeclRefExpr>(Cast.Children[0],
657 SourceSelectionKind::InsideSelection);
658 const auto &POE2 = checkNode<PseudoObjectExpr>(
659 SRE.Children[1], SourceSelectionKind::InsideSelection,
660 /*NumChildren=*/1);
661 const auto &PRE = checkNode<ObjCPropertyRefExpr>(
662 POE2.Children[0], SourceSelectionKind::InsideSelection,
663 /*NumChildren=*/1);
664 const auto &Cast2 = checkNode<ImplicitCastExpr>(
665 PRE.Children[0], SourceSelectionKind::InsideSelection,
666 /*NumChildren=*/1);
667 checkNode<DeclRefExpr>(Cast2.Children[0],
668 SourceSelectionKind::InsideSelection);
669 checkNode<DeclRefExpr>(BinOp.Children[1],
670 SourceSelectionKind::InsideSelection);
672 SelectionFinderVisitor::Lang_OBJC);
675 TEST(ASTSelectionFinder, SimpleCodeRangeASTSelection) {
676 StringRef Source = R"(void f(int x, int y) {
677 int z = x;
678 f(2, 3);
679 if (x == 0) {
680 return;
682 x = 1;
683 return;
685 void f2() {
686 int m = 0;
689 // No selection range.
690 findSelectedASTNodesWithRange(
691 Source, {2, 2}, None,
692 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
693 EXPECT_TRUE(Node);
694 Optional<CodeRangeASTSelection> SelectedCode =
695 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
696 EXPECT_FALSE(SelectedCode);
698 findSelectedASTNodesWithRange(
699 Source, {2, 2}, FileRange{{2, 2}, {2, 2}},
700 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
701 EXPECT_TRUE(Node);
702 Optional<CodeRangeASTSelection> SelectedCode =
703 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
704 EXPECT_FALSE(SelectedCode);
706 // Range that spans multiple functions is an invalid code range.
707 findSelectedASTNodesWithRange(
708 Source, {2, 2}, FileRange{{7, 2}, {12, 1}},
709 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
710 EXPECT_TRUE(Node);
711 Optional<CodeRangeASTSelection> SelectedCode =
712 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
713 EXPECT_FALSE(SelectedCode);
715 // Just 'z = x;':
716 findSelectedASTNodesWithRange(
717 Source, {2, 2}, FileRange{{2, 2}, {2, 13}},
718 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
719 EXPECT_TRUE(Node);
720 Optional<CodeRangeASTSelection> SelectedCode =
721 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
722 EXPECT_TRUE(SelectedCode);
723 EXPECT_EQ(SelectedCode->size(), 1u);
724 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
725 ArrayRef<SelectedASTNode::ReferenceType> Parents =
726 SelectedCode->getParents();
727 EXPECT_EQ(Parents.size(), 3u);
728 EXPECT_TRUE(
729 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
730 // Function 'f' definition.
731 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
732 // Function body of function 'F'.
733 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
735 // From 'f(2,3)' until just before 'x = 1;':
736 findSelectedASTNodesWithRange(
737 Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
738 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
739 EXPECT_TRUE(Node);
740 Optional<CodeRangeASTSelection> SelectedCode =
741 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
742 EXPECT_TRUE(SelectedCode);
743 EXPECT_EQ(SelectedCode->size(), 2u);
744 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
745 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
746 ArrayRef<SelectedASTNode::ReferenceType> Parents =
747 SelectedCode->getParents();
748 EXPECT_EQ(Parents.size(), 3u);
749 EXPECT_TRUE(
750 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
751 // Function 'f' definition.
752 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
753 // Function body of function 'F'.
754 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
756 // From 'f(2,3)' until just before ';' in 'x = 1;':
757 findSelectedASTNodesWithRange(
758 Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
759 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
760 EXPECT_TRUE(Node);
761 Optional<CodeRangeASTSelection> SelectedCode =
762 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
763 EXPECT_TRUE(SelectedCode);
764 EXPECT_EQ(SelectedCode->size(), 3u);
765 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
766 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
767 EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[2]));
769 // From the middle of 'int z = 3' until the middle of 'x = 1;':
770 findSelectedASTNodesWithRange(
771 Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
772 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
773 EXPECT_TRUE(Node);
774 EXPECT_TRUE(Node);
775 Optional<CodeRangeASTSelection> SelectedCode =
776 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
777 EXPECT_TRUE(SelectedCode);
778 EXPECT_EQ(SelectedCode->size(), 4u);
779 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
780 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[1]));
781 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[2]));
782 EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[3]));
786 TEST(ASTSelectionFinder, OutOfBodyCodeRange) {
787 StringRef Source = R"(
788 int codeRange = 2 + 3;
790 // '2+3' expression.
791 findSelectedASTNodesWithRange(
792 Source, {2, 17}, FileRange{{2, 17}, {2, 22}},
793 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
794 EXPECT_TRUE(Node);
795 Optional<CodeRangeASTSelection> SelectedCode =
796 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
797 EXPECT_TRUE(SelectedCode);
798 EXPECT_EQ(SelectedCode->size(), 1u);
799 EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[0]));
800 ArrayRef<SelectedASTNode::ReferenceType> Parents =
801 SelectedCode->getParents();
802 EXPECT_EQ(Parents.size(), 2u);
803 EXPECT_TRUE(
804 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
805 // Variable 'codeRange'.
806 EXPECT_TRUE(isa<VarDecl>(Parents[1].get().Node.get<Decl>()));
810 TEST(ASTSelectionFinder, SelectVarDeclStmt) {
811 StringRef Source = R"(
812 void f() {
814 int a;
818 // 'int a'
819 findSelectedASTNodesWithRange(
820 Source, {4, 8}, FileRange{{4, 8}, {4, 14}},
821 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
822 EXPECT_TRUE(Node);
823 Optional<CodeRangeASTSelection> SelectedCode =
824 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
825 EXPECT_TRUE(SelectedCode);
826 EXPECT_EQ(SelectedCode->size(), 1u);
827 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
828 ArrayRef<SelectedASTNode::ReferenceType> Parents =
829 SelectedCode->getParents();
830 EXPECT_EQ(Parents.size(), 4u);
831 EXPECT_TRUE(
832 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
833 // Function 'f' definition.
834 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
835 // Function body of function 'F'.
836 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
837 // Compound statement in body of 'F'.
838 EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
842 TEST(ASTSelectionFinder, SelectEntireDeclStmtRange) {
843 StringRef Source = R"(
844 void f(int x, int y) {
845 int a = x * y;
848 // 'int a = x * y'
849 findSelectedASTNodesWithRange(
850 Source, {3, 4}, FileRange{{3, 4}, {3, 17}},
851 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
852 EXPECT_TRUE(Node);
853 Optional<CodeRangeASTSelection> SelectedCode =
854 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
855 EXPECT_TRUE(SelectedCode);
856 EXPECT_EQ(SelectedCode->size(), 1u);
857 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
858 ArrayRef<SelectedASTNode::ReferenceType> Parents =
859 SelectedCode->getParents();
860 EXPECT_EQ(Parents.size(), 3u);
861 EXPECT_TRUE(
862 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
863 // Function 'f' definition.
864 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
865 // Function body of function 'F'.
866 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
870 TEST(ASTSelectionFinder, SelectEntireDeclStmtRangeWithMultipleDecls) {
871 StringRef Source = R"(
872 void f(int x, int y) {
873 int a = x * y, b = x - y;
876 // 'b = x - y'
877 findSelectedASTNodesWithRange(
878 Source, {3, 19}, FileRange{{3, 19}, {3, 28}},
879 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
880 EXPECT_TRUE(Node);
881 Optional<CodeRangeASTSelection> SelectedCode =
882 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
883 EXPECT_TRUE(SelectedCode);
884 EXPECT_EQ(SelectedCode->size(), 1u);
885 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
886 ArrayRef<SelectedASTNode::ReferenceType> Parents =
887 SelectedCode->getParents();
888 EXPECT_EQ(Parents.size(), 3u);
889 EXPECT_TRUE(
890 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
891 // Function 'f' definition.
892 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
893 // Function body of function 'F'.
894 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
898 TEST(ASTSelectionFinder, SimpleCodeRangeASTSelectionInObjCMethod) {
899 StringRef Source = R"(@interface I @end
900 @implementation I
901 - (void) f:(int)x with:(int) y {
902 int z = x;
903 [self f: 2 with: 3];
904 if (x == 0) {
905 return;
907 x = 1;
908 return;
910 - (void)f2 {
911 int m = 0;
913 @end
915 // Range that spans multiple methods is an invalid code range.
916 findSelectedASTNodesWithRange(
917 Source, {9, 2}, FileRange{{9, 2}, {13, 1}},
918 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
919 EXPECT_TRUE(Node);
920 Optional<CodeRangeASTSelection> SelectedCode =
921 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
922 EXPECT_FALSE(SelectedCode);
924 SelectionFinderVisitor::Lang_OBJC);
925 // Just 'z = x;':
926 findSelectedASTNodesWithRange(
927 Source, {4, 2}, FileRange{{4, 2}, {4, 13}},
928 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
929 EXPECT_TRUE(Node);
930 Optional<CodeRangeASTSelection> SelectedCode =
931 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
932 EXPECT_TRUE(SelectedCode);
933 EXPECT_EQ(SelectedCode->size(), 1u);
934 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
935 ArrayRef<SelectedASTNode::ReferenceType> Parents =
936 SelectedCode->getParents();
937 EXPECT_EQ(Parents.size(), 4u);
938 EXPECT_TRUE(
939 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
940 // 'I' @implementation.
941 EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
942 // Function 'f' definition.
943 EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
944 // Function body of function 'F'.
945 EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
947 SelectionFinderVisitor::Lang_OBJC);
948 // From '[self f: 2 with: 3]' until just before 'x = 1;':
949 findSelectedASTNodesWithRange(
950 Source, {5, 2}, FileRange{{5, 2}, {9, 1}},
951 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
952 EXPECT_TRUE(Node);
953 Optional<CodeRangeASTSelection> SelectedCode =
954 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
955 EXPECT_TRUE(SelectedCode);
956 EXPECT_EQ(SelectedCode->size(), 2u);
957 EXPECT_TRUE(isa<ObjCMessageExpr>((*SelectedCode)[0]));
958 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
959 ArrayRef<SelectedASTNode::ReferenceType> Parents =
960 SelectedCode->getParents();
961 EXPECT_EQ(Parents.size(), 4u);
962 EXPECT_TRUE(
963 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
964 // 'I' @implementation.
965 EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
966 // Function 'f' definition.
967 EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
968 // Function body of function 'F'.
969 EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
971 SelectionFinderVisitor::Lang_OBJC);
974 TEST(ASTSelectionFinder, CanonicalizeObjCStringLiteral) {
975 StringRef Source = R"(
976 void foo() {
977 (void)@"test";
980 // Just '"test"':
981 findSelectedASTNodesWithRange(
982 Source, {3, 10}, FileRange{{3, 10}, {3, 16}},
983 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
984 EXPECT_TRUE(Node);
985 Optional<CodeRangeASTSelection> SelectedCode =
986 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
987 EXPECT_TRUE(SelectedCode);
988 EXPECT_EQ(SelectedCode->size(), 1u);
989 EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
991 SelectionFinderVisitor::Lang_OBJC);
992 // Just 'test':
993 findSelectedASTNodesWithRange(
994 Source, {3, 11}, FileRange{{3, 11}, {3, 15}},
995 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
996 EXPECT_TRUE(Node);
997 Optional<CodeRangeASTSelection> SelectedCode =
998 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
999 EXPECT_TRUE(SelectedCode);
1000 EXPECT_EQ(SelectedCode->size(), 1u);
1001 EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
1003 SelectionFinderVisitor::Lang_OBJC);
1006 TEST(ASTSelectionFinder, CanonicalizeMemberCalleeToCall) {
1007 StringRef Source = R"(
1008 class AClass { public:
1009 void method();
1010 int afield;
1011 void selectWholeCallWhenJustMethodSelected(int &i) {
1012 method();
1015 void selectWholeCallWhenJustMethodSelected() {
1016 AClass a;
1017 a.method();
1019 void dontSelectArgument(AClass &a) {
1020 a.selectWholeCallWhenJustMethodSelected(a.afield);
1023 // Just 'method' with implicit 'this':
1024 findSelectedASTNodesWithRange(
1025 Source, {6, 5}, FileRange{{6, 5}, {6, 11}},
1026 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
1027 EXPECT_TRUE(Node);
1028 Optional<CodeRangeASTSelection> SelectedCode =
1029 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1030 EXPECT_TRUE(SelectedCode);
1031 EXPECT_EQ(SelectedCode->size(), 1u);
1032 EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1034 // Just 'method':
1035 findSelectedASTNodesWithRange(
1036 Source, {11, 5}, FileRange{{11, 5}, {11, 11}},
1037 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
1038 EXPECT_TRUE(Node);
1039 Optional<CodeRangeASTSelection> SelectedCode =
1040 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1041 EXPECT_TRUE(SelectedCode);
1042 EXPECT_EQ(SelectedCode->size(), 1u);
1043 EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1045 // Just 'afield', which should not select the call.
1046 findSelectedASTNodesWithRange(
1047 Source, {14, 5}, FileRange{{14, 45}, {14, 51}},
1048 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
1049 EXPECT_TRUE(Node);
1050 Optional<CodeRangeASTSelection> SelectedCode =
1051 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1052 EXPECT_TRUE(SelectedCode);
1053 EXPECT_EQ(SelectedCode->size(), 1u);
1054 EXPECT_FALSE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1058 TEST(ASTSelectionFinder, CanonicalizeFuncCalleeToCall) {
1059 StringRef Source = R"(
1060 void function();
1062 void test() {
1063 function();
1066 // Just 'function':
1067 findSelectedASTNodesWithRange(
1068 Source, {5, 3}, FileRange{{5, 3}, {5, 11}},
1069 [](SourceRange SelectionRange, Optional<SelectedASTNode> Node) {
1070 EXPECT_TRUE(Node);
1071 Node->dump();
1072 Optional<CodeRangeASTSelection> SelectedCode =
1073 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1074 EXPECT_TRUE(SelectedCode);
1075 EXPECT_EQ(SelectedCode->size(), 1u);
1076 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
1077 EXPECT_TRUE(isa<CompoundStmt>(
1078 SelectedCode->getParents()[SelectedCode->getParents().size() - 1]
1079 .get()
1080 .Node.get<Stmt>()));
1084 } // end anonymous namespace