Clang Project

clang_source_code/unittests/Tooling/ASTSelectionTest.cpp
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//===----------------------------------------------------------------------===//
8
9#include "TestVisitor.h"
10#include "clang/Basic/SourceManager.h"
11#include "clang/Tooling/Refactoring/ASTSelection.h"
12
13using namespace clang;
14using namespace tooling;
15
16namespace {
17
18struct FileLocation {
19  unsigned LineColumn;
20
21  SourceLocation translate(const SourceManager &SM) {
22    return SM.translateLineCol(SM.getMainFileID(), LineColumn);
23  }
24};
25
26using FileRange = std::pair<FileLocationFileLocation>;
27
28class SelectionFinderVisitor : public TestVisitor<SelectionFinderVisitor> {
29  FileLocation Location;
30  Optional<FileRangeSelectionRange;
31  llvm::function_ref<void(SourceRange SelectionRange,
32                          Optional<SelectedASTNode>)>
33      Consumer;
34
35public:
36  SelectionFinderVisitor(FileLocation Location,
37                         Optional<FileRangeSelectionRange,
38                         llvm::function_ref<void(SourceRange SelectionRange,
39                                                 Optional<SelectedASTNode>)>
40                             Consumer)
41      : Location(Location), SelectionRange(SelectionRange), Consumer(Consumer) {
42  }
43
44  bool VisitTranslationUnitDecl(const TranslationUnitDecl *TU) {
45    const ASTContext &Context = TU->getASTContext();
46    const SourceManager &SM = Context.getSourceManager();
47
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(LocLoc);
55    }
56    Consumer(SelRange, findSelectedASTNodes(Context, SelRange));
57    return false;
58  }
59};
60
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.
66void findSelectedASTNodesWithRange(
67    StringRef SourceFileLocation LocationOptional<FileRangeSelectionRange,
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));
75}
76
77void findSelectedASTNodes(
78    StringRef SourceFileLocation LocationOptional<FileRangeSelectionRange,
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));
86      },
87      Language);
88}
89
90void checkNodeImpl(bool IsTypeMatchedconst SelectedASTNode &Node,
91                   SourceSelectionKind SelectionKindunsigned NumChildren) {
92  ASSERT_TRUE(IsTypeMatched);
93  EXPECT_EQ(Node.Children.size(), NumChildren);
94  ASSERT_EQ(Node.SelectionKindSelectionKind);
95}
96
97void checkDeclName(const SelectedASTNode &NodeStringRef Name) {
98  const auto *ND = Node.Node.get<NamedDecl>();
99  EXPECT_TRUE(!!ND);
100  ASSERT_EQ(ND->getName(), Name);
101}
102
103template <typename T>
104const SelectedASTNode &
105checkNode(const SelectedASTNode &StmtNodeSourceSelectionKind SelectionKind,
106          unsigned NumChildren = 0,
107          typename std::enable_if<std::is_base_of<Stmt, T>::value, T>::type
108              *StmtOverloadChecker = nullptr) {
109  checkNodeImpl(isa<T>(StmtNode.Node.get<Stmt>()), StmtNode, SelectionKind,
110                NumChildren);
111  return StmtNode;
112}
113
114template <typename T>
115const SelectedASTNode &
116checkNode(const SelectedASTNode &DeclNodeSourceSelectionKind SelectionKind,
117          unsigned NumChildren = 0StringRef Name = "",
118          typename std::enable_if<std::is_base_of<Decl, T>::value, T>::type
119              *DeclOverloadChecker = nullptr) {
120  checkNodeImpl(isa<T>(DeclNode.Node.get<Decl>()), DeclNode, SelectionKind,
121                NumChildren);
122  if (!Name.empty())
123    checkDeclName(DeclNode, Name);
124  return DeclNode;
125}
126
127struct ForAllChildrenOf {
128  const SelectedASTNode &Node;
129
130  static void childKindVerifier(const SelectedASTNode &Node,
131                                SourceSelectionKind SelectionKind) {
132    for (const SelectedASTNode &Child : Node.Children) {
133      ASSERT_EQ(Node.SelectionKindSelectionKind);
134      childKindVerifier(ChildSelectionKind);
135    }
136  }
137
138public:
139  ForAllChildrenOf(const SelectedASTNode &Node) : Node(Node) {}
140
141  void shouldHaveSelectionKind(SourceSelectionKind Kind) {
142    childKindVerifier(NodeKind);
143  }
144};
145
146ForAllChildrenOf allChildrenOf(const SelectedASTNode &Node) {
147  return ForAllChildrenOf(Node);
148}
149
150TEST(ASTSelectionFinder, CursorNoSelection) {
151  findSelectedASTNodes(
152      " void f() { }", {11}, None,
153      [](Optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
154}
155
156TEST(ASTSelectionFinder, CursorAtStartOfFunction) {
157  findSelectedASTNodes(
158      "void f() { }", {11}, 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");
165
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");
171      });
172}
173
174TEST(ASTSelectionFinder, RangeNoSelection) {
175  findSelectedASTNodes(
176      " void f() { }", {11}, FileRange{{11}, {11}},
177      [](Optional<SelectedASTNodeNode) { EXPECT_FALSE(Node); });
178  findSelectedASTNodes(
179      "  void f() { }", {11}, FileRange{{11}, {12}},
180      [](Optional<SelectedASTNodeNode) { EXPECT_FALSE(Node); });
181}
182
183TEST(ASTSelectionFinder, EmptyRangeFallbackToCursor) {
184  findSelectedASTNodes("void f() { }", {11}, FileRange{{11}, {11}},
185                       [](Optional<SelectedASTNodeNode) {
186                         EXPECT_TRUE(Node);
187                         checkNode<FunctionDecl>(
188                             Node->Children[0],
189                             SourceSelectionKind::ContainsSelection,
190                             /*NumChildren=*/0/*Name=*/"f");
191                       });
192}
193
194TEST(ASTSelectionFinder, WholeFunctionSelection) {
195  StringRef Source = "int f(int x) { return x;\n}\nvoid f2() { }";
196  // From 'int' until just after '}':
197
198  findSelectedASTNodes(
199      Source, {11}, FileRange{{11}, {22}},
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);
219      });
220
221  // From 'int' until just before '}':
222  findSelectedASTNodes(
223      Source, {21}, FileRange{{11}, {21}},
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);
236      });
237  // From '{' until just after '}':
238  findSelectedASTNodes(
239      Source, {114}, FileRange{{114}, {22}},
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);
252      });
253  // From 'x' until just after '}':
254  findSelectedASTNodes(
255      Source, {22}, FileRange{{111}, {22}},
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);
270      });
271}
272
273TEST(ASTSelectionFinder, MultipleFunctionSelection) {
274  StringRef Source = R"(void f0() {
275}
276void f1() { }
277void f2() { }
278void f3() { }
279)";
280  auto SelectedF1F2 = [](Optional<SelectedASTNodeNode) {
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");
289  };
290  // Just after '}' of f0 and just before 'void' of f3:
291  findSelectedASTNodes(Source, {22}, FileRange{{22}, {51}}, SelectedF1F2);
292  // Just before 'void' of f1 and just after '}' of f2:
293  findSelectedASTNodes(Source, {31}, FileRange{{31}, {414}},
294                       SelectedF1F2);
295}
296
297TEST(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;
303  }
304  x = 1;
305  return;
306})";
307  // From 'f(2,3)' until just before 'x = 1;':
308  findSelectedASTNodes(
309      Source, {32}, FileRange{{32}, {71}},
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);
327      });
328  // From 'f(2,3)' until just before ';' in 'x = 1;':
329  findSelectedASTNodes(
330      Source, {32}, FileRange{{32}, {78}},
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);
349      });
350  // From the middle of 'int z = 3' until the middle of 'x = 1;':
351  findSelectedASTNodes(
352      Source, {210}, FileRange{{210}, {75}},
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);
374      });
375}
376
377TEST(ASTSelectionFinder, SelectionInFunctionInObjCImplementation) {
378  StringRef Source = R"(
379@interface I
380@end
381@implementation I
382
383int notSelected() { }
384
385int selected(int x) {
386  return x;
387}
388
389@end
390@implementation I(Cat)
391
392void catF() { }
393
394@end
395
396void outerFunction() { }
397)";
398  // Just the 'x' expression in 'selected':
399  findSelectedASTNodes(
400      Source, {910}, FileRange{{910}, {911}},
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);
412      },
413      SelectionFinderVisitor::Lang_OBJC);
414  // The entire 'catF':
415  findSelectedASTNodes(
416      Source, {151}, FileRange{{151}, {1516}},
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);
428      },
429      SelectionFinderVisitor::Lang_OBJC);
430  // From the line before 'selected' to the line after 'catF':
431  findSelectedASTNodes(
432      Source, {161}, FileRange{{71}, {161}},
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);
452      },
453      SelectionFinderVisitor::Lang_OBJC);
454  // Just the 'outer' function:
455  findSelectedASTNodes(Source, {191}, FileRange{{191}, {1925}},
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");
463                       },
464                       SelectionFinderVisitor::Lang_OBJC);
465}
466
467TEST(ASTSelectionFinder, FunctionInObjCImplementationCarefulWithEarlyExit) {
468  StringRef Source = R"(
469@interface I
470@end
471@implementation I
472
473void selected() {
474}
475
476- (void) method { }
477
478@end
479)";
480  // Just 'selected'
481  findSelectedASTNodes(
482      Source, {61}, FileRange{{61}, {72}},
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");
492      },
493      SelectionFinderVisitor::Lang_OBJC);
494}
495
496TEST(ASTSelectionFinder, AvoidImplicitDeclarations) {
497  StringRef Source = R"(
498struct Copy {
499  int x;
500};
501void foo() {
502  Copy x;
503  Copy y = x;
504}
505)";
506  // The entire struct 'Copy':
507  findSelectedASTNodes(
508      Source, {21}, FileRange{{21}, {43}},
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);
517      });
518}
519
520TEST(ASTSelectionFinder, CorrectEndForObjectiveCImplementation) {
521  StringRef Source = R"(
522@interface I
523@end
524@implementation I
525@ end
526)";
527  // Just after '@ end'
528  findSelectedASTNodes(Source, {56}, 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);
535                       },
536                       SelectionFinderVisitor::Lang_OBJC);
537}
538
539const 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);
549}
550
551TEST(ASTSelectionFinder, SelectObjectiveCPseudoObjectExprs) {
552  StringRef Source = R"(
553@interface I
554@property(readwrite) int prop;
555@end
556void selectProp(I *i) {
557(void)i.prop;
558i.prop = 21;
559}
560
561
562@interface NSMutableArray
563- (id)objectAtIndexedSubscript:(unsigned int)index;
564- (void)setObject:(id)object atIndexedSubscript:(unsigned int)index;
565@end
566
567void selectSubscript(NSMutableArray *array, I *i) {
568  (void)array[10];
569  array[i.prop] = i;
570}
571)";
572  // Just 'i.prop'.
573  findSelectedASTNodes(
574      Source, {67}, FileRange{{67}, {613}},
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);
591      },
592      SelectionFinderVisitor::Lang_OBJC);
593  // Just 'i.prop = 21'
594  findSelectedASTNodes(
595      Source, {71}, FileRange{{71}, {712}},
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);
614      },
615      SelectionFinderVisitor::Lang_OBJC);
616  // Just 'array[10]'
617  findSelectedASTNodes(
618      Source, {179}, FileRange{{179}, {1718}},
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);
637      },
638      SelectionFinderVisitor::Lang_OBJC);
639  // Just 'array[i.prop] = array'
640  findSelectedASTNodes(
641      Source, {183}, FileRange{{183}, {1820}},
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);
671      },
672      SelectionFinderVisitor::Lang_OBJC);
673}
674
675TEST(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;
681  }
682  x = 1;
683  return;
684}
685void f2() {
686  int m = 0;
687}
688)";
689  // No selection range.
690  findSelectedASTNodesWithRange(
691      Source, {22}, 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);
697      });
698  findSelectedASTNodesWithRange(
699      Source, {22}, FileRange{{22}, {22}},
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);
705      });
706  // Range that spans multiple functions is an invalid code range.
707  findSelectedASTNodesWithRange(
708      Source, {22}, FileRange{{72}, {121}},
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);
714      });
715  // Just 'z = x;':
716  findSelectedASTNodesWithRange(
717      Source, {22}, FileRange{{22}, {213}},
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>()));
734      });
735  // From 'f(2,3)' until just before 'x = 1;':
736  findSelectedASTNodesWithRange(
737      Source, {32}, FileRange{{32}, {71}},
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>()));
755      });
756  // From 'f(2,3)' until just before ';' in 'x = 1;':
757  findSelectedASTNodesWithRange(
758      Source, {32}, FileRange{{32}, {78}},
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]));
768      });
769  // From the middle of 'int z = 3' until the middle of 'x = 1;':
770  findSelectedASTNodesWithRange(
771      Source, {210}, FileRange{{210}, {75}},
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]));
783      });
784}
785
786TEST(ASTSelectionFinder, OutOfBodyCodeRange) {
787  StringRef Source = R"(
788int codeRange = 2 + 3;
789)";
790  // '2+3' expression.
791  findSelectedASTNodesWithRange(
792      Source, {217}, FileRange{{217}, {222}},
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>()));
807      });
808}
809
810TEST(ASTSelectionFinder, SelectVarDeclStmt) {
811  StringRef Source = R"(
812void f() {
813   {
814       int a;
815   }
816}
817)";
818  // 'int a'
819  findSelectedASTNodesWithRange(
820      Source, {48}, FileRange{{48}, {414}},
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>()));
839      });
840}
841
842TEST(ASTSelectionFinder, SelectEntireDeclStmtRange) {
843  StringRef Source = R"(
844void f(int x, int y) {
845   int a = x * y;
846}
847)";
848  // 'int a = x * y'
849  findSelectedASTNodesWithRange(
850      Source, {34}, FileRange{{34}, {317}},
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>()));
867      });
868}
869
870TEST(ASTSelectionFinder, SelectEntireDeclStmtRangeWithMultipleDecls) {
871  StringRef Source = R"(
872void f(int x, int y) {
873   int a = x * y, b = x - y;
874}
875)";
876  // 'b = x - y'
877  findSelectedASTNodesWithRange(
878      Source, {319}, FileRange{{319}, {328}},
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>()));
895      });
896}
897
898TEST(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;
906  }
907  x = 1;
908  return;
909}
910- (void)f2 {
911  int m = 0;
912}
913@end
914)";
915  // Range that spans multiple methods is an invalid code range.
916  findSelectedASTNodesWithRange(
917      Source, {92}, FileRange{{92}, {131}},
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);
923      },
924      SelectionFinderVisitor::Lang_OBJC);
925  // Just 'z = x;':
926  findSelectedASTNodesWithRange(
927      Source, {42}, FileRange{{42}, {413}},
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>()));
946      },
947      SelectionFinderVisitor::Lang_OBJC);
948  // From '[self f: 2 with: 3]' until just before 'x = 1;':
949  findSelectedASTNodesWithRange(
950      Source, {52}, FileRange{{52}, {91}},
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>()));
970      },
971      SelectionFinderVisitor::Lang_OBJC);
972}
973
974TEST(ASTSelectionFinder, CanonicalizeObjCStringLiteral) {
975  StringRef Source = R"(
976void foo() {
977  (void)@"test";
978}
979      )";
980  // Just '"test"':
981  findSelectedASTNodesWithRange(
982      Source, {310}, FileRange{{310}, {316}},
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]));
990      },
991      SelectionFinderVisitor::Lang_OBJC);
992  // Just 'test':
993  findSelectedASTNodesWithRange(
994      Source, {311}, FileRange{{311}, {315}},
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]));
1002      },
1003      SelectionFinderVisitor::Lang_OBJC);
1004}
1005
1006TEST(ASTSelectionFinder, CanonicalizeMemberCalleeToCall) {
1007  StringRef Source = R"(
1008class AClass { public:
1009  void method();
1010  int afield;
1011  void selectWholeCallWhenJustMethodSelected(int &i) {
1012    method();
1013  }
1014};
1015void selectWholeCallWhenJustMethodSelected() {
1016  AClass a;
1017  a.method();
1018}
1019void dontSelectArgument(AClass &a) {
1020  a.selectWholeCallWhenJustMethodSelected(a.afield);
1021}
1022     )";
1023  // Just 'method' with implicit 'this':
1024  findSelectedASTNodesWithRange(
1025      Source, {65}, FileRange{{65}, {611}},
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]));
1033      });
1034  // Just 'method':
1035  findSelectedASTNodesWithRange(
1036      Source, {115}, FileRange{{115}, {1111}},
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]));
1044      });
1045  // Just 'afield', which should not select the call.
1046  findSelectedASTNodesWithRange(
1047      Source, {145}, FileRange{{1445}, {1451}},
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]));
1055      });
1056}
1057
1058TEST(ASTSelectionFinder, CanonicalizeFuncCalleeToCall) {
1059  StringRef Source = R"(
1060void function();
1061
1062void test() {
1063  function();
1064}
1065     )";
1066  // Just 'function':
1067  findSelectedASTNodesWithRange(
1068      Source, {53}, FileRange{{53}, {511}},
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>()));
1081      });
1082}
1083
1084// end anonymous namespace
1085