[TableGen] Fix validateOperandClass for non Phyical Reg (#118146)
[llvm-project.git] / clang / unittests / Tooling / ASTSelectionTest.cpp
blob1897bc15196ec25837602da923c9d8234fb9203e
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"
12 #include <optional>
14 using namespace clang;
15 using namespace tooling;
17 namespace {
19 struct FileLocation {
20 unsigned Line, Column;
22 SourceLocation translate(const SourceManager &SM) {
23 return SM.translateLineCol(SM.getMainFileID(), Line, Column);
27 using FileRange = std::pair<FileLocation, FileLocation>;
29 class SelectionFinderVisitor : public TestVisitor {
30 FileLocation Location;
31 std::optional<FileRange> SelectionRange;
32 llvm::function_ref<void(SourceRange SelectionRange,
33 std::optional<SelectedASTNode>)>
34 Consumer;
36 public:
37 SelectionFinderVisitor(
38 FileLocation Location, std::optional<FileRange> SelectionRange,
39 llvm::function_ref<void(SourceRange SelectionRange,
40 std::optional<SelectedASTNode>)>
41 Consumer)
42 : Location(Location), SelectionRange(SelectionRange), Consumer(Consumer) {
45 bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) override {
46 const ASTContext &Context = TU->getASTContext();
47 const SourceManager &SM = Context.getSourceManager();
49 SourceRange SelRange;
50 if (SelectionRange) {
51 SelRange = SourceRange(SelectionRange->first.translate(SM),
52 SelectionRange->second.translate(SM));
53 } else {
54 SourceLocation Loc = Location.translate(SM);
55 SelRange = SourceRange(Loc, Loc);
57 Consumer(SelRange, findSelectedASTNodes(Context, SelRange));
58 return false;
62 /// This is a test utility function that computes the AST selection at the
63 /// given location with an optional selection range.
64 ///
65 /// A location roughly corresponds to a cursor location in an editor, while
66 /// the optional range corresponds to the selection range in an editor.
67 void findSelectedASTNodesWithRange(
68 StringRef Source, FileLocation Location,
69 std::optional<FileRange> SelectionRange,
70 llvm::function_ref<void(SourceRange SelectionRange,
71 std::optional<SelectedASTNode>)>
72 Consumer,
73 SelectionFinderVisitor::Language Language =
74 SelectionFinderVisitor::Lang_CXX11) {
75 SelectionFinderVisitor Visitor(Location, SelectionRange, Consumer);
76 EXPECT_TRUE(Visitor.runOver(Source, Language));
79 void findSelectedASTNodes(
80 StringRef Source, FileLocation Location,
81 std::optional<FileRange> SelectionRange,
82 llvm::function_ref<void(std::optional<SelectedASTNode>)> Consumer,
83 SelectionFinderVisitor::Language Language =
84 SelectionFinderVisitor::Lang_CXX11) {
85 findSelectedASTNodesWithRange(
86 Source, Location, SelectionRange,
87 [&](SourceRange, std::optional<SelectedASTNode> Selection) {
88 Consumer(std::move(Selection));
90 Language);
93 void checkNodeImpl(bool IsTypeMatched, const SelectedASTNode &Node,
94 SourceSelectionKind SelectionKind, unsigned NumChildren) {
95 ASSERT_TRUE(IsTypeMatched);
96 EXPECT_EQ(Node.Children.size(), NumChildren);
97 ASSERT_EQ(Node.SelectionKind, SelectionKind);
100 void checkDeclName(const SelectedASTNode &Node, StringRef Name) {
101 const auto *ND = Node.Node.get<NamedDecl>();
102 EXPECT_TRUE(!!ND);
103 ASSERT_EQ(ND->getName(), Name);
106 template <typename T>
107 const SelectedASTNode &
108 checkNode(const SelectedASTNode &StmtNode, SourceSelectionKind SelectionKind,
109 unsigned NumChildren = 0,
110 std::enable_if_t<std::is_base_of_v<Stmt, T>, T> *StmtOverloadChecker =
111 nullptr) {
112 checkNodeImpl(isa<T>(StmtNode.Node.get<Stmt>()), StmtNode, SelectionKind,
113 NumChildren);
114 return StmtNode;
117 template <typename T>
118 const SelectedASTNode &
119 checkNode(const SelectedASTNode &DeclNode, SourceSelectionKind SelectionKind,
120 unsigned NumChildren = 0, StringRef Name = "",
121 std::enable_if_t<std::is_base_of_v<Decl, T>, T> *DeclOverloadChecker =
122 nullptr) {
123 checkNodeImpl(isa<T>(DeclNode.Node.get<Decl>()), DeclNode, SelectionKind,
124 NumChildren);
125 if (!Name.empty())
126 checkDeclName(DeclNode, Name);
127 return DeclNode;
130 struct ForAllChildrenOf {
131 const SelectedASTNode &Node;
133 static void childKindVerifier(const SelectedASTNode &Node,
134 SourceSelectionKind SelectionKind) {
135 for (const SelectedASTNode &Child : Node.Children) {
136 ASSERT_EQ(Node.SelectionKind, SelectionKind);
137 childKindVerifier(Child, SelectionKind);
141 public:
142 ForAllChildrenOf(const SelectedASTNode &Node) : Node(Node) {}
144 void shouldHaveSelectionKind(SourceSelectionKind Kind) {
145 childKindVerifier(Node, Kind);
149 ForAllChildrenOf allChildrenOf(const SelectedASTNode &Node) {
150 return ForAllChildrenOf(Node);
153 TEST(ASTSelectionFinder, CursorNoSelection) {
154 findSelectedASTNodes(
155 " void f() { }", {1, 1}, std::nullopt,
156 [](std::optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
159 TEST(ASTSelectionFinder, CursorAtStartOfFunction) {
160 findSelectedASTNodes(
161 "void f() { }", {1, 1}, std::nullopt,
162 [](std::optional<SelectedASTNode> Node) {
163 EXPECT_TRUE(Node);
164 checkNode<TranslationUnitDecl>(*Node, SourceSelectionKind::None,
165 /*NumChildren=*/1);
166 checkNode<FunctionDecl>(Node->Children[0],
167 SourceSelectionKind::ContainsSelection,
168 /*NumChildren=*/0, /*Name=*/"f");
170 // Check that the dumping works.
171 std::string DumpValue;
172 llvm::raw_string_ostream OS(DumpValue);
173 Node->Children[0].dump(OS);
174 ASSERT_EQ(DumpValue, "FunctionDecl \"f\" contains-selection\n");
178 TEST(ASTSelectionFinder, RangeNoSelection) {
179 findSelectedASTNodes(
180 " void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
181 [](std::optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
182 findSelectedASTNodes(
183 " void f() { }", {1, 1}, FileRange{{1, 1}, {1, 2}},
184 [](std::optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
187 TEST(ASTSelectionFinder, EmptyRangeFallbackToCursor) {
188 findSelectedASTNodes("void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
189 [](std::optional<SelectedASTNode> Node) {
190 EXPECT_TRUE(Node);
191 checkNode<FunctionDecl>(
192 Node->Children[0],
193 SourceSelectionKind::ContainsSelection,
194 /*NumChildren=*/0, /*Name=*/"f");
198 TEST(ASTSelectionFinder, WholeFunctionSelection) {
199 StringRef Source = "int f(int x) { return x;\n}\nvoid f2() { }";
200 // From 'int' until just after '}':
202 findSelectedASTNodes(
203 Source, {1, 1}, FileRange{{1, 1}, {2, 2}},
204 [](std::optional<SelectedASTNode> Node) {
205 EXPECT_TRUE(Node);
206 EXPECT_EQ(Node->Children.size(), 1u);
207 const auto &Fn = checkNode<FunctionDecl>(
208 Node->Children[0], SourceSelectionKind::ContainsSelection,
209 /*NumChildren=*/2, /*Name=*/"f");
210 checkNode<ParmVarDecl>(Fn.Children[0],
211 SourceSelectionKind::InsideSelection);
212 const auto &Body = checkNode<CompoundStmt>(
213 Fn.Children[1], SourceSelectionKind::InsideSelection,
214 /*NumChildren=*/1);
215 const auto &Return = checkNode<ReturnStmt>(
216 Body.Children[0], SourceSelectionKind::InsideSelection,
217 /*NumChildren=*/1);
218 checkNode<ImplicitCastExpr>(Return.Children[0],
219 SourceSelectionKind::InsideSelection,
220 /*NumChildren=*/1);
221 checkNode<DeclRefExpr>(Return.Children[0].Children[0],
222 SourceSelectionKind::InsideSelection);
225 // From 'int' until just before '}':
226 findSelectedASTNodes(
227 Source, {2, 1}, FileRange{{1, 1}, {2, 1}},
228 [](std::optional<SelectedASTNode> Node) {
229 EXPECT_TRUE(Node);
230 EXPECT_EQ(Node->Children.size(), 1u);
231 const auto &Fn = checkNode<FunctionDecl>(
232 Node->Children[0], SourceSelectionKind::ContainsSelection,
233 /*NumChildren=*/2, /*Name=*/"f");
234 const auto &Body = checkNode<CompoundStmt>(
235 Fn.Children[1], SourceSelectionKind::ContainsSelectionEnd,
236 /*NumChildren=*/1);
237 checkNode<ReturnStmt>(Body.Children[0],
238 SourceSelectionKind::InsideSelection,
239 /*NumChildren=*/1);
241 // From '{' until just after '}':
242 findSelectedASTNodes(
243 Source, {1, 14}, FileRange{{1, 14}, {2, 2}},
244 [](std::optional<SelectedASTNode> Node) {
245 EXPECT_TRUE(Node);
246 EXPECT_EQ(Node->Children.size(), 1u);
247 const auto &Fn = checkNode<FunctionDecl>(
248 Node->Children[0], SourceSelectionKind::ContainsSelection,
249 /*NumChildren=*/1, /*Name=*/"f");
250 const auto &Body = checkNode<CompoundStmt>(
251 Fn.Children[0], SourceSelectionKind::ContainsSelection,
252 /*NumChildren=*/1);
253 checkNode<ReturnStmt>(Body.Children[0],
254 SourceSelectionKind::InsideSelection,
255 /*NumChildren=*/1);
257 // From 'x' until just after '}':
258 findSelectedASTNodes(
259 Source, {2, 2}, FileRange{{1, 11}, {2, 2}},
260 [](std::optional<SelectedASTNode> Node) {
261 EXPECT_TRUE(Node);
262 EXPECT_EQ(Node->Children.size(), 1u);
263 const auto &Fn = checkNode<FunctionDecl>(
264 Node->Children[0], SourceSelectionKind::ContainsSelection,
265 /*NumChildren=*/2, /*Name=*/"f");
266 checkNode<ParmVarDecl>(Fn.Children[0],
267 SourceSelectionKind::ContainsSelectionStart);
268 const auto &Body = checkNode<CompoundStmt>(
269 Fn.Children[1], SourceSelectionKind::InsideSelection,
270 /*NumChildren=*/1);
271 checkNode<ReturnStmt>(Body.Children[0],
272 SourceSelectionKind::InsideSelection,
273 /*NumChildren=*/1);
277 TEST(ASTSelectionFinder, MultipleFunctionSelection) {
278 StringRef Source = R"(void f0() {
280 void f1() { }
281 void f2() { }
282 void f3() { }
284 auto SelectedF1F2 = [](std::optional<SelectedASTNode> Node) {
285 EXPECT_TRUE(Node);
286 EXPECT_EQ(Node->Children.size(), 2u);
287 checkNode<FunctionDecl>(Node->Children[0],
288 SourceSelectionKind::InsideSelection,
289 /*NumChildren=*/1, /*Name=*/"f1");
290 checkNode<FunctionDecl>(Node->Children[1],
291 SourceSelectionKind::InsideSelection,
292 /*NumChildren=*/1, /*Name=*/"f2");
294 // Just after '}' of f0 and just before 'void' of f3:
295 findSelectedASTNodes(Source, {2, 2}, FileRange{{2, 2}, {5, 1}}, SelectedF1F2);
296 // Just before 'void' of f1 and just after '}' of f2:
297 findSelectedASTNodes(Source, {3, 1}, FileRange{{3, 1}, {4, 14}},
298 SelectedF1F2);
301 TEST(ASTSelectionFinder, MultipleStatementSelection) {
302 StringRef Source = R"(void f(int x, int y) {
303 int z = x;
304 f(2, 3);
305 if (x == 0) {
306 return;
308 x = 1;
309 return;
310 })";
311 // From 'f(2,3)' until just before 'x = 1;':
312 findSelectedASTNodes(
313 Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
314 [](std::optional<SelectedASTNode> Node) {
315 EXPECT_TRUE(Node);
316 EXPECT_EQ(Node->Children.size(), 1u);
317 const auto &Fn = checkNode<FunctionDecl>(
318 Node->Children[0], SourceSelectionKind::ContainsSelection,
319 /*NumChildren=*/1, /*Name=*/"f");
320 const auto &Body = checkNode<CompoundStmt>(
321 Fn.Children[0], SourceSelectionKind::ContainsSelection,
322 /*NumChildren=*/2);
323 allChildrenOf(checkNode<CallExpr>(Body.Children[0],
324 SourceSelectionKind::InsideSelection,
325 /*NumChildren=*/3))
326 .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
327 allChildrenOf(checkNode<IfStmt>(Body.Children[1],
328 SourceSelectionKind::InsideSelection,
329 /*NumChildren=*/2))
330 .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
332 // From 'f(2,3)' until just before ';' in 'x = 1;':
333 findSelectedASTNodes(
334 Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
335 [](std::optional<SelectedASTNode> Node) {
336 EXPECT_TRUE(Node);
337 EXPECT_EQ(Node->Children.size(), 1u);
338 const auto &Fn = checkNode<FunctionDecl>(
339 Node->Children[0], SourceSelectionKind::ContainsSelection,
340 /*NumChildren=*/1, /*Name=*/"f");
341 const auto &Body = checkNode<CompoundStmt>(
342 Fn.Children[0], SourceSelectionKind::ContainsSelection,
343 /*NumChildren=*/3);
344 checkNode<CallExpr>(Body.Children[0],
345 SourceSelectionKind::InsideSelection,
346 /*NumChildren=*/3);
347 checkNode<IfStmt>(Body.Children[1],
348 SourceSelectionKind::InsideSelection,
349 /*NumChildren=*/2);
350 checkNode<BinaryOperator>(Body.Children[2],
351 SourceSelectionKind::InsideSelection,
352 /*NumChildren=*/2);
354 // From the middle of 'int z = 3' until the middle of 'x = 1;':
355 findSelectedASTNodes(
356 Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
357 [](std::optional<SelectedASTNode> Node) {
358 EXPECT_TRUE(Node);
359 EXPECT_EQ(Node->Children.size(), 1u);
360 const auto &Fn = checkNode<FunctionDecl>(
361 Node->Children[0], SourceSelectionKind::ContainsSelection,
362 /*NumChildren=*/1, /*Name=*/"f");
363 const auto &Body = checkNode<CompoundStmt>(
364 Fn.Children[0], SourceSelectionKind::ContainsSelection,
365 /*NumChildren=*/4);
366 checkNode<DeclStmt>(Body.Children[0],
367 SourceSelectionKind::ContainsSelectionStart,
368 /*NumChildren=*/1);
369 checkNode<CallExpr>(Body.Children[1],
370 SourceSelectionKind::InsideSelection,
371 /*NumChildren=*/3);
372 checkNode<IfStmt>(Body.Children[2],
373 SourceSelectionKind::InsideSelection,
374 /*NumChildren=*/2);
375 checkNode<BinaryOperator>(Body.Children[3],
376 SourceSelectionKind::ContainsSelectionEnd,
377 /*NumChildren=*/1);
381 TEST(ASTSelectionFinder, SelectionInFunctionInObjCImplementation) {
382 StringRef Source = R"(
383 @interface I
384 @end
385 @implementation I
387 int notSelected() { }
389 int selected(int x) {
390 return x;
393 @end
394 @implementation I(Cat)
396 void catF() { }
398 @end
400 void outerFunction() { }
402 // Just the 'x' expression in 'selected':
403 findSelectedASTNodes(
404 Source, {9, 10}, FileRange{{9, 10}, {9, 11}},
405 [](std::optional<SelectedASTNode> Node) {
406 EXPECT_TRUE(Node);
407 EXPECT_EQ(Node->Children.size(), 1u);
408 const auto &Impl = checkNode<ObjCImplementationDecl>(
409 Node->Children[0], SourceSelectionKind::ContainsSelection,
410 /*NumChildren=*/1, /*Name=*/"I");
411 const auto &Fn = checkNode<FunctionDecl>(
412 Impl.Children[0], SourceSelectionKind::ContainsSelection,
413 /*NumChildren=*/1, /*Name=*/"selected");
414 allChildrenOf(Fn).shouldHaveSelectionKind(
415 SourceSelectionKind::ContainsSelection);
417 SelectionFinderVisitor::Lang_OBJC);
418 // The entire 'catF':
419 findSelectedASTNodes(
420 Source, {15, 1}, FileRange{{15, 1}, {15, 16}},
421 [](std::optional<SelectedASTNode> Node) {
422 EXPECT_TRUE(Node);
423 EXPECT_EQ(Node->Children.size(), 1u);
424 const auto &Impl = checkNode<ObjCCategoryImplDecl>(
425 Node->Children[0], SourceSelectionKind::ContainsSelection,
426 /*NumChildren=*/1, /*Name=*/"Cat");
427 const auto &Fn = checkNode<FunctionDecl>(
428 Impl.Children[0], SourceSelectionKind::ContainsSelection,
429 /*NumChildren=*/1, /*Name=*/"catF");
430 allChildrenOf(Fn).shouldHaveSelectionKind(
431 SourceSelectionKind::ContainsSelection);
433 SelectionFinderVisitor::Lang_OBJC);
434 // From the line before 'selected' to the line after 'catF':
435 findSelectedASTNodes(
436 Source, {16, 1}, FileRange{{7, 1}, {16, 1}},
437 [](std::optional<SelectedASTNode> Node) {
438 EXPECT_TRUE(Node);
439 EXPECT_EQ(Node->Children.size(), 2u);
440 const auto &Impl = checkNode<ObjCImplementationDecl>(
441 Node->Children[0], SourceSelectionKind::ContainsSelectionStart,
442 /*NumChildren=*/1, /*Name=*/"I");
443 const auto &Selected = checkNode<FunctionDecl>(
444 Impl.Children[0], SourceSelectionKind::InsideSelection,
445 /*NumChildren=*/2, /*Name=*/"selected");
446 allChildrenOf(Selected).shouldHaveSelectionKind(
447 SourceSelectionKind::InsideSelection);
448 const auto &Cat = checkNode<ObjCCategoryImplDecl>(
449 Node->Children[1], SourceSelectionKind::ContainsSelectionEnd,
450 /*NumChildren=*/1, /*Name=*/"Cat");
451 const auto &CatF = checkNode<FunctionDecl>(
452 Cat.Children[0], SourceSelectionKind::InsideSelection,
453 /*NumChildren=*/1, /*Name=*/"catF");
454 allChildrenOf(CatF).shouldHaveSelectionKind(
455 SourceSelectionKind::InsideSelection);
457 SelectionFinderVisitor::Lang_OBJC);
458 // Just the 'outer' function:
459 findSelectedASTNodes(
460 Source, {19, 1}, FileRange{{19, 1}, {19, 25}},
461 [](std::optional<SelectedASTNode> Node) {
462 EXPECT_TRUE(Node);
463 EXPECT_EQ(Node->Children.size(), 1u);
464 checkNode<FunctionDecl>(Node->Children[0],
465 SourceSelectionKind::ContainsSelection,
466 /*NumChildren=*/1, /*Name=*/"outerFunction");
468 SelectionFinderVisitor::Lang_OBJC);
471 TEST(ASTSelectionFinder, FunctionInObjCImplementationCarefulWithEarlyExit) {
472 StringRef Source = R"(
473 @interface I
474 @end
475 @implementation I
477 void selected() {
480 - (void) method { }
482 @end
484 // Just 'selected'
485 findSelectedASTNodes(
486 Source, {6, 1}, FileRange{{6, 1}, {7, 2}},
487 [](std::optional<SelectedASTNode> Node) {
488 EXPECT_TRUE(Node);
489 EXPECT_EQ(Node->Children.size(), 1u);
490 const auto &Impl = checkNode<ObjCImplementationDecl>(
491 Node->Children[0], SourceSelectionKind::ContainsSelection,
492 /*NumChildren=*/1, /*Name=*/"I");
493 checkNode<FunctionDecl>(Impl.Children[0],
494 SourceSelectionKind::ContainsSelection,
495 /*NumChildren=*/1, /*Name=*/"selected");
497 SelectionFinderVisitor::Lang_OBJC);
500 TEST(ASTSelectionFinder, AvoidImplicitDeclarations) {
501 StringRef Source = R"(
502 struct Copy {
503 int x;
505 void foo() {
506 Copy x;
507 Copy y = x;
510 // The entire struct 'Copy':
511 findSelectedASTNodes(
512 Source, {2, 1}, FileRange{{2, 1}, {4, 3}},
513 [](std::optional<SelectedASTNode> Node) {
514 EXPECT_TRUE(Node);
515 EXPECT_EQ(Node->Children.size(), 1u);
516 const auto &Record = checkNode<CXXRecordDecl>(
517 Node->Children[0], SourceSelectionKind::InsideSelection,
518 /*NumChildren=*/1, /*Name=*/"Copy");
519 checkNode<FieldDecl>(Record.Children[0],
520 SourceSelectionKind::InsideSelection);
524 TEST(ASTSelectionFinder, CorrectEndForObjectiveCImplementation) {
525 StringRef Source = R"(
526 @interface I
527 @end
528 @implementation I
529 @ end
531 // Just after '@ end'
532 findSelectedASTNodes(
533 Source, {5, 6}, std::nullopt,
534 [](std::optional<SelectedASTNode> Node) {
535 EXPECT_TRUE(Node);
536 EXPECT_EQ(Node->Children.size(), 1u);
537 checkNode<ObjCImplementationDecl>(
538 Node->Children[0], SourceSelectionKind::ContainsSelection);
540 SelectionFinderVisitor::Lang_OBJC);
543 const SelectedASTNode &checkFnBody(const std::optional<SelectedASTNode> &Node,
544 StringRef Name) {
545 EXPECT_TRUE(Node);
546 EXPECT_EQ(Node->Children.size(), 1u);
547 const auto &Fn = checkNode<FunctionDecl>(
548 Node->Children[0], SourceSelectionKind::ContainsSelection,
549 /*NumChildren=*/1, Name);
550 return checkNode<CompoundStmt>(Fn.Children[0],
551 SourceSelectionKind::ContainsSelection,
552 /*NumChildren=*/1);
555 TEST(ASTSelectionFinder, SelectObjectiveCPseudoObjectExprs) {
556 StringRef Source = R"(
557 @interface I
558 @property(readwrite) int prop;
559 @end
560 void selectProp(I *i) {
561 (void)i.prop;
562 i.prop = 21;
566 @interface NSMutableArray
567 - (id)objectAtIndexedSubscript:(unsigned int)index;
568 - (void)setObject:(id)object atIndexedSubscript:(unsigned int)index;
569 @end
571 void selectSubscript(NSMutableArray *array, I *i) {
572 (void)array[10];
573 array[i.prop] = i;
576 // Just 'i.prop'.
577 findSelectedASTNodes(
578 Source, {6, 7}, FileRange{{6, 7}, {6, 13}},
579 [](std::optional<SelectedASTNode> Node) {
580 const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
581 const auto &CCast = checkNode<CStyleCastExpr>(
582 CS.Children[0], SourceSelectionKind::ContainsSelection,
583 /*NumChildren=*/1);
584 const auto &POE = checkNode<PseudoObjectExpr>(
585 CCast.Children[0], SourceSelectionKind::ContainsSelection,
586 /*NumChildren=*/1);
587 const auto &PRE = checkNode<ObjCPropertyRefExpr>(
588 POE.Children[0], SourceSelectionKind::ContainsSelection,
589 /*NumChildren=*/1);
590 const auto &Cast = checkNode<ImplicitCastExpr>(
591 PRE.Children[0], SourceSelectionKind::InsideSelection,
592 /*NumChildren=*/1);
593 checkNode<DeclRefExpr>(Cast.Children[0],
594 SourceSelectionKind::InsideSelection);
596 SelectionFinderVisitor::Lang_OBJC);
597 // Just 'i.prop = 21'
598 findSelectedASTNodes(
599 Source, {7, 1}, FileRange{{7, 1}, {7, 12}},
600 [](std::optional<SelectedASTNode> Node) {
601 const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
602 const auto &POE = checkNode<PseudoObjectExpr>(
603 CS.Children[0], SourceSelectionKind::ContainsSelection,
604 /*NumChildren=*/1);
605 const auto &BinOp = checkNode<BinaryOperator>(
606 POE.Children[0], SourceSelectionKind::ContainsSelection,
607 /*NumChildren=*/2);
608 const auto &PRE = checkNode<ObjCPropertyRefExpr>(
609 BinOp.Children[0], SourceSelectionKind::InsideSelection,
610 /*NumChildren=*/1);
611 const auto &Cast = checkNode<ImplicitCastExpr>(
612 PRE.Children[0], SourceSelectionKind::InsideSelection,
613 /*NumChildren=*/1);
614 checkNode<DeclRefExpr>(Cast.Children[0],
615 SourceSelectionKind::InsideSelection);
616 checkNode<IntegerLiteral>(BinOp.Children[1],
617 SourceSelectionKind::InsideSelection);
619 SelectionFinderVisitor::Lang_OBJC);
620 // Just 'array[10]'
621 findSelectedASTNodes(
622 Source, {17, 9}, FileRange{{17, 9}, {17, 18}},
623 [](std::optional<SelectedASTNode> Node) {
624 const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
625 const auto &CCast = checkNode<CStyleCastExpr>(
626 CS.Children[0], SourceSelectionKind::ContainsSelection,
627 /*NumChildren=*/1);
628 const auto &POE = checkNode<PseudoObjectExpr>(
629 CCast.Children[0], SourceSelectionKind::ContainsSelection,
630 /*NumChildren=*/1);
631 const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
632 POE.Children[0], SourceSelectionKind::ContainsSelection,
633 /*NumChildren=*/2);
634 const auto &Cast = checkNode<ImplicitCastExpr>(
635 SRE.Children[0], SourceSelectionKind::InsideSelection,
636 /*NumChildren=*/1);
637 checkNode<DeclRefExpr>(Cast.Children[0],
638 SourceSelectionKind::InsideSelection);
639 checkNode<IntegerLiteral>(SRE.Children[1],
640 SourceSelectionKind::InsideSelection);
642 SelectionFinderVisitor::Lang_OBJC);
643 // Just 'array[i.prop] = array'
644 findSelectedASTNodes(
645 Source, {18, 3}, FileRange{{18, 3}, {18, 20}},
646 [](std::optional<SelectedASTNode> Node) {
647 const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
648 const auto &POE = checkNode<PseudoObjectExpr>(
649 CS.Children[0], SourceSelectionKind::ContainsSelection,
650 /*NumChildren=*/1);
651 const auto &BinOp = checkNode<BinaryOperator>(
652 POE.Children[0], SourceSelectionKind::ContainsSelection,
653 /*NumChildren=*/2);
654 const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
655 BinOp.Children[0], SourceSelectionKind::InsideSelection,
656 /*NumChildren=*/2);
657 const auto &Cast = checkNode<ImplicitCastExpr>(
658 SRE.Children[0], SourceSelectionKind::InsideSelection,
659 /*NumChildren=*/1);
660 checkNode<DeclRefExpr>(Cast.Children[0],
661 SourceSelectionKind::InsideSelection);
662 const auto &POE2 = checkNode<PseudoObjectExpr>(
663 SRE.Children[1], SourceSelectionKind::InsideSelection,
664 /*NumChildren=*/1);
665 const auto &PRE = checkNode<ObjCPropertyRefExpr>(
666 POE2.Children[0], SourceSelectionKind::InsideSelection,
667 /*NumChildren=*/1);
668 const auto &Cast2 = checkNode<ImplicitCastExpr>(
669 PRE.Children[0], SourceSelectionKind::InsideSelection,
670 /*NumChildren=*/1);
671 checkNode<DeclRefExpr>(Cast2.Children[0],
672 SourceSelectionKind::InsideSelection);
673 checkNode<DeclRefExpr>(BinOp.Children[1],
674 SourceSelectionKind::InsideSelection);
676 SelectionFinderVisitor::Lang_OBJC);
679 TEST(ASTSelectionFinder, SimpleCodeRangeASTSelection) {
680 StringRef Source = R"(void f(int x, int y) {
681 int z = x;
682 f(2, 3);
683 if (x == 0) {
684 return;
686 x = 1;
687 return;
689 void f2() {
690 int m = 0;
693 // No selection range.
694 findSelectedASTNodesWithRange(
695 Source, {2, 2}, std::nullopt,
696 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
697 EXPECT_TRUE(Node);
698 std::optional<CodeRangeASTSelection> SelectedCode =
699 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
700 EXPECT_FALSE(SelectedCode);
702 findSelectedASTNodesWithRange(
703 Source, {2, 2}, FileRange{{2, 2}, {2, 2}},
704 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
705 EXPECT_TRUE(Node);
706 std::optional<CodeRangeASTSelection> SelectedCode =
707 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
708 EXPECT_FALSE(SelectedCode);
710 // Range that spans multiple functions is an invalid code range.
711 findSelectedASTNodesWithRange(
712 Source, {2, 2}, FileRange{{7, 2}, {12, 1}},
713 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
714 EXPECT_TRUE(Node);
715 std::optional<CodeRangeASTSelection> SelectedCode =
716 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
717 EXPECT_FALSE(SelectedCode);
719 // Just 'z = x;':
720 findSelectedASTNodesWithRange(
721 Source, {2, 2}, FileRange{{2, 2}, {2, 13}},
722 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
723 EXPECT_TRUE(Node);
724 std::optional<CodeRangeASTSelection> SelectedCode =
725 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
726 EXPECT_TRUE(SelectedCode);
727 EXPECT_EQ(SelectedCode->size(), 1u);
728 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
729 ArrayRef<SelectedASTNode::ReferenceType> Parents =
730 SelectedCode->getParents();
731 EXPECT_EQ(Parents.size(), 3u);
732 EXPECT_TRUE(
733 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
734 // Function 'f' definition.
735 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
736 // Function body of function 'F'.
737 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
739 // From 'f(2,3)' until just before 'x = 1;':
740 findSelectedASTNodesWithRange(
741 Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
742 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
743 EXPECT_TRUE(Node);
744 std::optional<CodeRangeASTSelection> SelectedCode =
745 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
746 EXPECT_TRUE(SelectedCode);
747 EXPECT_EQ(SelectedCode->size(), 2u);
748 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
749 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
750 ArrayRef<SelectedASTNode::ReferenceType> Parents =
751 SelectedCode->getParents();
752 EXPECT_EQ(Parents.size(), 3u);
753 EXPECT_TRUE(
754 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
755 // Function 'f' definition.
756 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
757 // Function body of function 'F'.
758 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
760 // From 'f(2,3)' until just before ';' in 'x = 1;':
761 findSelectedASTNodesWithRange(
762 Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
763 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
764 EXPECT_TRUE(Node);
765 std::optional<CodeRangeASTSelection> SelectedCode =
766 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
767 EXPECT_TRUE(SelectedCode);
768 EXPECT_EQ(SelectedCode->size(), 3u);
769 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
770 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
771 EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[2]));
773 // From the middle of 'int z = 3' until the middle of 'x = 1;':
774 findSelectedASTNodesWithRange(
775 Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
776 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
777 EXPECT_TRUE(Node);
778 EXPECT_TRUE(Node);
779 std::optional<CodeRangeASTSelection> SelectedCode =
780 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
781 EXPECT_TRUE(SelectedCode);
782 EXPECT_EQ(SelectedCode->size(), 4u);
783 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
784 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[1]));
785 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[2]));
786 EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[3]));
790 TEST(ASTSelectionFinder, OutOfBodyCodeRange) {
791 StringRef Source = R"(
792 int codeRange = 2 + 3;
794 // '2+3' expression.
795 findSelectedASTNodesWithRange(
796 Source, {2, 17}, FileRange{{2, 17}, {2, 22}},
797 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
798 EXPECT_TRUE(Node);
799 std::optional<CodeRangeASTSelection> SelectedCode =
800 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
801 EXPECT_TRUE(SelectedCode);
802 EXPECT_EQ(SelectedCode->size(), 1u);
803 EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[0]));
804 ArrayRef<SelectedASTNode::ReferenceType> Parents =
805 SelectedCode->getParents();
806 EXPECT_EQ(Parents.size(), 2u);
807 EXPECT_TRUE(
808 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
809 // Variable 'codeRange'.
810 EXPECT_TRUE(isa<VarDecl>(Parents[1].get().Node.get<Decl>()));
814 TEST(ASTSelectionFinder, SelectVarDeclStmt) {
815 StringRef Source = R"(
816 void f() {
818 int a;
822 // 'int a'
823 findSelectedASTNodesWithRange(
824 Source, {4, 8}, FileRange{{4, 8}, {4, 14}},
825 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
826 EXPECT_TRUE(Node);
827 std::optional<CodeRangeASTSelection> SelectedCode =
828 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
829 EXPECT_TRUE(SelectedCode);
830 EXPECT_EQ(SelectedCode->size(), 1u);
831 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
832 ArrayRef<SelectedASTNode::ReferenceType> Parents =
833 SelectedCode->getParents();
834 EXPECT_EQ(Parents.size(), 4u);
835 EXPECT_TRUE(
836 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
837 // Function 'f' definition.
838 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
839 // Function body of function 'F'.
840 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
841 // Compound statement in body of 'F'.
842 EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
846 TEST(ASTSelectionFinder, SelectEntireDeclStmtRange) {
847 StringRef Source = R"(
848 void f(int x, int y) {
849 int a = x * y;
852 // 'int a = x * y'
853 findSelectedASTNodesWithRange(
854 Source, {3, 4}, FileRange{{3, 4}, {3, 17}},
855 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
856 EXPECT_TRUE(Node);
857 std::optional<CodeRangeASTSelection> SelectedCode =
858 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
859 EXPECT_TRUE(SelectedCode);
860 EXPECT_EQ(SelectedCode->size(), 1u);
861 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
862 ArrayRef<SelectedASTNode::ReferenceType> Parents =
863 SelectedCode->getParents();
864 EXPECT_EQ(Parents.size(), 3u);
865 EXPECT_TRUE(
866 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
867 // Function 'f' definition.
868 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
869 // Function body of function 'F'.
870 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
874 TEST(ASTSelectionFinder, SelectEntireDeclStmtRangeWithMultipleDecls) {
875 StringRef Source = R"(
876 void f(int x, int y) {
877 int a = x * y, b = x - y;
880 // 'b = x - y'
881 findSelectedASTNodesWithRange(
882 Source, {3, 19}, FileRange{{3, 19}, {3, 28}},
883 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
884 EXPECT_TRUE(Node);
885 std::optional<CodeRangeASTSelection> SelectedCode =
886 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
887 EXPECT_TRUE(SelectedCode);
888 EXPECT_EQ(SelectedCode->size(), 1u);
889 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
890 ArrayRef<SelectedASTNode::ReferenceType> Parents =
891 SelectedCode->getParents();
892 EXPECT_EQ(Parents.size(), 3u);
893 EXPECT_TRUE(
894 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
895 // Function 'f' definition.
896 EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
897 // Function body of function 'F'.
898 EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
902 TEST(ASTSelectionFinder, SimpleCodeRangeASTSelectionInObjCMethod) {
903 StringRef Source = R"(@interface I @end
904 @implementation I
905 - (void) f:(int)x with:(int) y {
906 int z = x;
907 [self f: 2 with: 3];
908 if (x == 0) {
909 return;
911 x = 1;
912 return;
914 - (void)f2 {
915 int m = 0;
917 @end
919 // Range that spans multiple methods is an invalid code range.
920 findSelectedASTNodesWithRange(
921 Source, {9, 2}, FileRange{{9, 2}, {13, 1}},
922 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
923 EXPECT_TRUE(Node);
924 std::optional<CodeRangeASTSelection> SelectedCode =
925 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
926 EXPECT_FALSE(SelectedCode);
928 SelectionFinderVisitor::Lang_OBJC);
929 // Just 'z = x;':
930 findSelectedASTNodesWithRange(
931 Source, {4, 2}, FileRange{{4, 2}, {4, 13}},
932 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
933 EXPECT_TRUE(Node);
934 std::optional<CodeRangeASTSelection> SelectedCode =
935 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
936 EXPECT_TRUE(SelectedCode);
937 EXPECT_EQ(SelectedCode->size(), 1u);
938 EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
939 ArrayRef<SelectedASTNode::ReferenceType> Parents =
940 SelectedCode->getParents();
941 EXPECT_EQ(Parents.size(), 4u);
942 EXPECT_TRUE(
943 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
944 // 'I' @implementation.
945 EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
946 // Function 'f' definition.
947 EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
948 // Function body of function 'F'.
949 EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
951 SelectionFinderVisitor::Lang_OBJC);
952 // From '[self f: 2 with: 3]' until just before 'x = 1;':
953 findSelectedASTNodesWithRange(
954 Source, {5, 2}, FileRange{{5, 2}, {9, 1}},
955 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
956 EXPECT_TRUE(Node);
957 std::optional<CodeRangeASTSelection> SelectedCode =
958 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
959 EXPECT_TRUE(SelectedCode);
960 EXPECT_EQ(SelectedCode->size(), 2u);
961 EXPECT_TRUE(isa<ObjCMessageExpr>((*SelectedCode)[0]));
962 EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
963 ArrayRef<SelectedASTNode::ReferenceType> Parents =
964 SelectedCode->getParents();
965 EXPECT_EQ(Parents.size(), 4u);
966 EXPECT_TRUE(
967 isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
968 // 'I' @implementation.
969 EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
970 // Function 'f' definition.
971 EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
972 // Function body of function 'F'.
973 EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
975 SelectionFinderVisitor::Lang_OBJC);
978 TEST(ASTSelectionFinder, CanonicalizeObjCStringLiteral) {
979 StringRef Source = R"(
980 void foo() {
981 (void)@"test";
984 // Just '"test"':
985 findSelectedASTNodesWithRange(
986 Source, {3, 10}, FileRange{{3, 10}, {3, 16}},
987 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
988 EXPECT_TRUE(Node);
989 std::optional<CodeRangeASTSelection> SelectedCode =
990 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
991 EXPECT_TRUE(SelectedCode);
992 EXPECT_EQ(SelectedCode->size(), 1u);
993 EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
995 SelectionFinderVisitor::Lang_OBJC);
996 // Just 'test':
997 findSelectedASTNodesWithRange(
998 Source, {3, 11}, FileRange{{3, 11}, {3, 15}},
999 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1000 EXPECT_TRUE(Node);
1001 std::optional<CodeRangeASTSelection> SelectedCode =
1002 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1003 EXPECT_TRUE(SelectedCode);
1004 EXPECT_EQ(SelectedCode->size(), 1u);
1005 EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
1007 SelectionFinderVisitor::Lang_OBJC);
1010 TEST(ASTSelectionFinder, CanonicalizeMemberCalleeToCall) {
1011 StringRef Source = R"(
1012 class AClass { public:
1013 void method();
1014 int afield;
1015 void selectWholeCallWhenJustMethodSelected(int &i) {
1016 method();
1019 void selectWholeCallWhenJustMethodSelected() {
1020 AClass a;
1021 a.method();
1023 void dontSelectArgument(AClass &a) {
1024 a.selectWholeCallWhenJustMethodSelected(a.afield);
1027 // Just 'method' with implicit 'this':
1028 findSelectedASTNodesWithRange(
1029 Source, {6, 5}, FileRange{{6, 5}, {6, 11}},
1030 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1031 EXPECT_TRUE(Node);
1032 std::optional<CodeRangeASTSelection> SelectedCode =
1033 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1034 EXPECT_TRUE(SelectedCode);
1035 EXPECT_EQ(SelectedCode->size(), 1u);
1036 EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1038 // Just 'method':
1039 findSelectedASTNodesWithRange(
1040 Source, {11, 5}, FileRange{{11, 5}, {11, 11}},
1041 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1042 EXPECT_TRUE(Node);
1043 std::optional<CodeRangeASTSelection> SelectedCode =
1044 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1045 EXPECT_TRUE(SelectedCode);
1046 EXPECT_EQ(SelectedCode->size(), 1u);
1047 EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1049 // Just 'afield', which should not select the call.
1050 findSelectedASTNodesWithRange(
1051 Source, {14, 5}, FileRange{{14, 45}, {14, 51}},
1052 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1053 EXPECT_TRUE(Node);
1054 std::optional<CodeRangeASTSelection> SelectedCode =
1055 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1056 EXPECT_TRUE(SelectedCode);
1057 EXPECT_EQ(SelectedCode->size(), 1u);
1058 EXPECT_FALSE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1062 TEST(ASTSelectionFinder, CanonicalizeFuncCalleeToCall) {
1063 StringRef Source = R"(
1064 void function();
1066 void test() {
1067 function();
1070 // Just 'function':
1071 findSelectedASTNodesWithRange(
1072 Source, {5, 3}, FileRange{{5, 3}, {5, 11}},
1073 [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1074 EXPECT_TRUE(Node);
1075 Node->dump();
1076 std::optional<CodeRangeASTSelection> SelectedCode =
1077 CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1078 EXPECT_TRUE(SelectedCode);
1079 EXPECT_EQ(SelectedCode->size(), 1u);
1080 EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
1081 EXPECT_TRUE(isa<CompoundStmt>(
1082 SelectedCode->getParents()[SelectedCode->getParents().size() - 1]
1083 .get()
1084 .Node.get<Stmt>()));
1088 } // end anonymous namespace