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