xref: /llvm-project/clang/unittests/Tooling/ASTSelectionTest.cpp (revision 12f78e740c5419f7d1fbcf8f2106e7a40cd1d6f7)
1a844f396SAlex Lorenz //===- unittest/Tooling/ASTSelectionTest.cpp ------------------------------===//
2a844f396SAlex Lorenz //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a844f396SAlex Lorenz //
7a844f396SAlex Lorenz //===----------------------------------------------------------------------===//
8a844f396SAlex Lorenz 
9a844f396SAlex Lorenz #include "TestVisitor.h"
10a844f396SAlex Lorenz #include "clang/Basic/SourceManager.h"
11a844f396SAlex Lorenz #include "clang/Tooling/Refactoring/ASTSelection.h"
12a1580d7bSKazu Hirata #include <optional>
13a844f396SAlex Lorenz 
14a844f396SAlex Lorenz using namespace clang;
15a844f396SAlex Lorenz using namespace tooling;
16a844f396SAlex Lorenz 
17a844f396SAlex Lorenz namespace {
18a844f396SAlex Lorenz 
19a844f396SAlex Lorenz struct FileLocation {
20a844f396SAlex Lorenz   unsigned Line, Column;
21a844f396SAlex Lorenz 
22a844f396SAlex Lorenz   SourceLocation translate(const SourceManager &SM) {
23a844f396SAlex Lorenz     return SM.translateLineCol(SM.getMainFileID(), Line, Column);
24a844f396SAlex Lorenz   }
25a844f396SAlex Lorenz };
26a844f396SAlex Lorenz 
27a844f396SAlex Lorenz using FileRange = std::pair<FileLocation, FileLocation>;
28a844f396SAlex Lorenz 
294e600751SSirraide class SelectionFinderVisitor : public TestVisitor {
30a844f396SAlex Lorenz   FileLocation Location;
316ad0788cSKazu Hirata   std::optional<FileRange> SelectionRange;
32cd6c7838SAlex Lorenz   llvm::function_ref<void(SourceRange SelectionRange,
336ad0788cSKazu Hirata                           std::optional<SelectedASTNode>)>
34cd6c7838SAlex Lorenz       Consumer;
35a844f396SAlex Lorenz 
36a844f396SAlex Lorenz public:
376ad0788cSKazu Hirata   SelectionFinderVisitor(
386ad0788cSKazu Hirata       FileLocation Location, std::optional<FileRange> SelectionRange,
39cd6c7838SAlex Lorenz       llvm::function_ref<void(SourceRange SelectionRange,
406ad0788cSKazu Hirata                               std::optional<SelectedASTNode>)>
41cd6c7838SAlex Lorenz           Consumer)
4239265ca8SAlex Lorenz       : Location(Location), SelectionRange(SelectionRange), Consumer(Consumer) {
4339265ca8SAlex Lorenz   }
44a844f396SAlex Lorenz 
454e600751SSirraide   bool VisitTranslationUnitDecl(TranslationUnitDecl *TU) override {
46a844f396SAlex Lorenz     const ASTContext &Context = TU->getASTContext();
47a844f396SAlex Lorenz     const SourceManager &SM = Context.getSourceManager();
48a844f396SAlex Lorenz 
49a844f396SAlex Lorenz     SourceRange SelRange;
50a844f396SAlex Lorenz     if (SelectionRange) {
51a844f396SAlex Lorenz       SelRange = SourceRange(SelectionRange->first.translate(SM),
52a844f396SAlex Lorenz                              SelectionRange->second.translate(SM));
53a844f396SAlex Lorenz     } else {
54a844f396SAlex Lorenz       SourceLocation Loc = Location.translate(SM);
55a844f396SAlex Lorenz       SelRange = SourceRange(Loc, Loc);
56a844f396SAlex Lorenz     }
57cd6c7838SAlex Lorenz     Consumer(SelRange, findSelectedASTNodes(Context, SelRange));
58a844f396SAlex Lorenz     return false;
59a844f396SAlex Lorenz   }
60a844f396SAlex Lorenz };
61a844f396SAlex Lorenz 
62ce781e40SAlex Lorenz /// This is a test utility function that computes the AST selection at the
63ce781e40SAlex Lorenz /// given location with an optional selection range.
64ce781e40SAlex Lorenz ///
65ce781e40SAlex Lorenz /// A location roughly corresponds to a cursor location in an editor, while
66ce781e40SAlex Lorenz /// the optional range corresponds to the selection range in an editor.
67cd6c7838SAlex Lorenz void findSelectedASTNodesWithRange(
686ad0788cSKazu Hirata     StringRef Source, FileLocation Location,
696ad0788cSKazu Hirata     std::optional<FileRange> SelectionRange,
70cd6c7838SAlex Lorenz     llvm::function_ref<void(SourceRange SelectionRange,
716ad0788cSKazu Hirata                             std::optional<SelectedASTNode>)>
72cd6c7838SAlex Lorenz         Consumer,
73cd6c7838SAlex Lorenz     SelectionFinderVisitor::Language Language =
74cd6c7838SAlex Lorenz         SelectionFinderVisitor::Lang_CXX11) {
75cd6c7838SAlex Lorenz   SelectionFinderVisitor Visitor(Location, SelectionRange, Consumer);
76cd6c7838SAlex Lorenz   EXPECT_TRUE(Visitor.runOver(Source, Language));
77cd6c7838SAlex Lorenz }
78cd6c7838SAlex Lorenz 
7939265ca8SAlex Lorenz void findSelectedASTNodes(
806ad0788cSKazu Hirata     StringRef Source, FileLocation Location,
816ad0788cSKazu Hirata     std::optional<FileRange> SelectionRange,
826ad0788cSKazu Hirata     llvm::function_ref<void(std::optional<SelectedASTNode>)> Consumer,
83a844f396SAlex Lorenz     SelectionFinderVisitor::Language Language =
84a844f396SAlex Lorenz         SelectionFinderVisitor::Lang_CXX11) {
85cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
86cd6c7838SAlex Lorenz       Source, Location, SelectionRange,
876ad0788cSKazu Hirata       [&](SourceRange, std::optional<SelectedASTNode> Selection) {
88cd6c7838SAlex Lorenz         Consumer(std::move(Selection));
89cd6c7838SAlex Lorenz       },
90cd6c7838SAlex Lorenz       Language);
91a844f396SAlex Lorenz }
92a844f396SAlex Lorenz 
93a844f396SAlex Lorenz void checkNodeImpl(bool IsTypeMatched, const SelectedASTNode &Node,
94a844f396SAlex Lorenz                    SourceSelectionKind SelectionKind, unsigned NumChildren) {
95a844f396SAlex Lorenz   ASSERT_TRUE(IsTypeMatched);
96a844f396SAlex Lorenz   EXPECT_EQ(Node.Children.size(), NumChildren);
97a844f396SAlex Lorenz   ASSERT_EQ(Node.SelectionKind, SelectionKind);
98a844f396SAlex Lorenz }
99a844f396SAlex Lorenz 
100a844f396SAlex Lorenz void checkDeclName(const SelectedASTNode &Node, StringRef Name) {
101a844f396SAlex Lorenz   const auto *ND = Node.Node.get<NamedDecl>();
102a844f396SAlex Lorenz   EXPECT_TRUE(!!ND);
103a844f396SAlex Lorenz   ASSERT_EQ(ND->getName(), Name);
104a844f396SAlex Lorenz }
105a844f396SAlex Lorenz 
106a844f396SAlex Lorenz template <typename T>
107108e41d9SNathan James const SelectedASTNode &
108108e41d9SNathan James checkNode(const SelectedASTNode &StmtNode, SourceSelectionKind SelectionKind,
109a844f396SAlex Lorenz           unsigned NumChildren = 0,
110108e41d9SNathan James           std::enable_if_t<std::is_base_of_v<Stmt, T>, T> *StmtOverloadChecker =
111027eb716SJustin Lebar               nullptr) {
112a844f396SAlex Lorenz   checkNodeImpl(isa<T>(StmtNode.Node.get<Stmt>()), StmtNode, SelectionKind,
113a844f396SAlex Lorenz                 NumChildren);
114a844f396SAlex Lorenz   return StmtNode;
115a844f396SAlex Lorenz }
116a844f396SAlex Lorenz 
117a844f396SAlex Lorenz template <typename T>
118108e41d9SNathan James const SelectedASTNode &
119108e41d9SNathan James checkNode(const SelectedASTNode &DeclNode, SourceSelectionKind SelectionKind,
120a844f396SAlex Lorenz           unsigned NumChildren = 0, StringRef Name = "",
121108e41d9SNathan James           std::enable_if_t<std::is_base_of_v<Decl, T>, T> *DeclOverloadChecker =
122027eb716SJustin Lebar               nullptr) {
123a844f396SAlex Lorenz   checkNodeImpl(isa<T>(DeclNode.Node.get<Decl>()), DeclNode, SelectionKind,
124a844f396SAlex Lorenz                 NumChildren);
125a844f396SAlex Lorenz   if (!Name.empty())
126a844f396SAlex Lorenz     checkDeclName(DeclNode, Name);
127a844f396SAlex Lorenz   return DeclNode;
128a844f396SAlex Lorenz }
129a844f396SAlex Lorenz 
130a844f396SAlex Lorenz struct ForAllChildrenOf {
131a844f396SAlex Lorenz   const SelectedASTNode &Node;
132a844f396SAlex Lorenz 
133a844f396SAlex Lorenz   static void childKindVerifier(const SelectedASTNode &Node,
134a844f396SAlex Lorenz                                 SourceSelectionKind SelectionKind) {
135a844f396SAlex Lorenz     for (const SelectedASTNode &Child : Node.Children) {
136a844f396SAlex Lorenz       ASSERT_EQ(Node.SelectionKind, SelectionKind);
137a844f396SAlex Lorenz       childKindVerifier(Child, SelectionKind);
138a844f396SAlex Lorenz     }
139a844f396SAlex Lorenz   }
140a844f396SAlex Lorenz 
141a844f396SAlex Lorenz public:
142a844f396SAlex Lorenz   ForAllChildrenOf(const SelectedASTNode &Node) : Node(Node) {}
143a844f396SAlex Lorenz 
144a844f396SAlex Lorenz   void shouldHaveSelectionKind(SourceSelectionKind Kind) {
145a844f396SAlex Lorenz     childKindVerifier(Node, Kind);
146a844f396SAlex Lorenz   }
147a844f396SAlex Lorenz };
148a844f396SAlex Lorenz 
149a844f396SAlex Lorenz ForAllChildrenOf allChildrenOf(const SelectedASTNode &Node) {
150a844f396SAlex Lorenz   return ForAllChildrenOf(Node);
151a844f396SAlex Lorenz }
152a844f396SAlex Lorenz 
153a844f396SAlex Lorenz TEST(ASTSelectionFinder, CursorNoSelection) {
15439265ca8SAlex Lorenz   findSelectedASTNodes(
155a41fbb1fSKazu Hirata       " void f() { }", {1, 1}, std::nullopt,
1566ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
157a844f396SAlex Lorenz }
158a844f396SAlex Lorenz 
159a844f396SAlex Lorenz TEST(ASTSelectionFinder, CursorAtStartOfFunction) {
16039265ca8SAlex Lorenz   findSelectedASTNodes(
1616ad0788cSKazu Hirata       "void f() { }", {1, 1}, std::nullopt,
1626ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
163a844f396SAlex Lorenz         EXPECT_TRUE(Node);
164a844f396SAlex Lorenz         checkNode<TranslationUnitDecl>(*Node, SourceSelectionKind::None,
165a844f396SAlex Lorenz                                        /*NumChildren=*/1);
166a844f396SAlex Lorenz         checkNode<FunctionDecl>(Node->Children[0],
167a844f396SAlex Lorenz                                 SourceSelectionKind::ContainsSelection,
168a844f396SAlex Lorenz                                 /*NumChildren=*/0, /*Name=*/"f");
169a844f396SAlex Lorenz 
170a844f396SAlex Lorenz         // Check that the dumping works.
171a844f396SAlex Lorenz         std::string DumpValue;
172a844f396SAlex Lorenz         llvm::raw_string_ostream OS(DumpValue);
173a844f396SAlex Lorenz         Node->Children[0].dump(OS);
174918972bdSJOE1994         ASSERT_EQ(DumpValue, "FunctionDecl \"f\" contains-selection\n");
17539265ca8SAlex Lorenz       });
176a844f396SAlex Lorenz }
177a844f396SAlex Lorenz 
178a844f396SAlex Lorenz TEST(ASTSelectionFinder, RangeNoSelection) {
17939265ca8SAlex Lorenz   findSelectedASTNodes(
18039265ca8SAlex Lorenz       " void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
1816ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
18239265ca8SAlex Lorenz   findSelectedASTNodes(
18339265ca8SAlex Lorenz       "  void f() { }", {1, 1}, FileRange{{1, 1}, {1, 2}},
1846ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) { EXPECT_FALSE(Node); });
185a844f396SAlex Lorenz }
186a844f396SAlex Lorenz 
187a844f396SAlex Lorenz TEST(ASTSelectionFinder, EmptyRangeFallbackToCursor) {
18839265ca8SAlex Lorenz   findSelectedASTNodes("void f() { }", {1, 1}, FileRange{{1, 1}, {1, 1}},
1896ad0788cSKazu Hirata                        [](std::optional<SelectedASTNode> Node) {
190a844f396SAlex Lorenz                          EXPECT_TRUE(Node);
19139265ca8SAlex Lorenz                          checkNode<FunctionDecl>(
19239265ca8SAlex Lorenz                              Node->Children[0],
193a844f396SAlex Lorenz                              SourceSelectionKind::ContainsSelection,
194a844f396SAlex Lorenz                              /*NumChildren=*/0, /*Name=*/"f");
19539265ca8SAlex Lorenz                        });
196a844f396SAlex Lorenz }
197a844f396SAlex Lorenz 
198a844f396SAlex Lorenz TEST(ASTSelectionFinder, WholeFunctionSelection) {
199a844f396SAlex Lorenz   StringRef Source = "int f(int x) { return x;\n}\nvoid f2() { }";
200a844f396SAlex Lorenz   // From 'int' until just after '}':
20139265ca8SAlex Lorenz 
20239265ca8SAlex Lorenz   findSelectedASTNodes(
20339265ca8SAlex Lorenz       Source, {1, 1}, FileRange{{1, 1}, {2, 2}},
2046ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
205a844f396SAlex Lorenz         EXPECT_TRUE(Node);
206a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
207a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
208a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
209a844f396SAlex Lorenz             /*NumChildren=*/2, /*Name=*/"f");
210a844f396SAlex Lorenz         checkNode<ParmVarDecl>(Fn.Children[0],
211a844f396SAlex Lorenz                                SourceSelectionKind::InsideSelection);
212a844f396SAlex Lorenz         const auto &Body = checkNode<CompoundStmt>(
213a844f396SAlex Lorenz             Fn.Children[1], SourceSelectionKind::InsideSelection,
214a844f396SAlex Lorenz             /*NumChildren=*/1);
215a844f396SAlex Lorenz         const auto &Return = checkNode<ReturnStmt>(
216a844f396SAlex Lorenz             Body.Children[0], SourceSelectionKind::InsideSelection,
217a844f396SAlex Lorenz             /*NumChildren=*/1);
218a844f396SAlex Lorenz         checkNode<ImplicitCastExpr>(Return.Children[0],
219a844f396SAlex Lorenz                                     SourceSelectionKind::InsideSelection,
220a844f396SAlex Lorenz                                     /*NumChildren=*/1);
221a844f396SAlex Lorenz         checkNode<DeclRefExpr>(Return.Children[0].Children[0],
222a844f396SAlex Lorenz                                SourceSelectionKind::InsideSelection);
22339265ca8SAlex Lorenz       });
22439265ca8SAlex Lorenz 
225a844f396SAlex Lorenz   // From 'int' until just before '}':
22639265ca8SAlex Lorenz   findSelectedASTNodes(
22739265ca8SAlex Lorenz       Source, {2, 1}, FileRange{{1, 1}, {2, 1}},
2286ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
229a844f396SAlex Lorenz         EXPECT_TRUE(Node);
230a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
231a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
232a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
233a844f396SAlex Lorenz             /*NumChildren=*/2, /*Name=*/"f");
234a844f396SAlex Lorenz         const auto &Body = checkNode<CompoundStmt>(
235a844f396SAlex Lorenz             Fn.Children[1], SourceSelectionKind::ContainsSelectionEnd,
236a844f396SAlex Lorenz             /*NumChildren=*/1);
237a844f396SAlex Lorenz         checkNode<ReturnStmt>(Body.Children[0],
238a844f396SAlex Lorenz                               SourceSelectionKind::InsideSelection,
239a844f396SAlex Lorenz                               /*NumChildren=*/1);
24039265ca8SAlex Lorenz       });
241a844f396SAlex Lorenz   // From '{' until just after '}':
24239265ca8SAlex Lorenz   findSelectedASTNodes(
24339265ca8SAlex Lorenz       Source, {1, 14}, FileRange{{1, 14}, {2, 2}},
2446ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
245a844f396SAlex Lorenz         EXPECT_TRUE(Node);
246a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
247a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
248a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
249a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"f");
250a844f396SAlex Lorenz         const auto &Body = checkNode<CompoundStmt>(
251a844f396SAlex Lorenz             Fn.Children[0], SourceSelectionKind::ContainsSelection,
252a844f396SAlex Lorenz             /*NumChildren=*/1);
253a844f396SAlex Lorenz         checkNode<ReturnStmt>(Body.Children[0],
254a844f396SAlex Lorenz                               SourceSelectionKind::InsideSelection,
255a844f396SAlex Lorenz                               /*NumChildren=*/1);
25639265ca8SAlex Lorenz       });
257a844f396SAlex Lorenz   // From 'x' until just after '}':
25839265ca8SAlex Lorenz   findSelectedASTNodes(
25939265ca8SAlex Lorenz       Source, {2, 2}, FileRange{{1, 11}, {2, 2}},
2606ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
261a844f396SAlex Lorenz         EXPECT_TRUE(Node);
262a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
263a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
264a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
265a844f396SAlex Lorenz             /*NumChildren=*/2, /*Name=*/"f");
266a844f396SAlex Lorenz         checkNode<ParmVarDecl>(Fn.Children[0],
267a844f396SAlex Lorenz                                SourceSelectionKind::ContainsSelectionStart);
268a844f396SAlex Lorenz         const auto &Body = checkNode<CompoundStmt>(
269a844f396SAlex Lorenz             Fn.Children[1], SourceSelectionKind::InsideSelection,
270a844f396SAlex Lorenz             /*NumChildren=*/1);
271a844f396SAlex Lorenz         checkNode<ReturnStmt>(Body.Children[0],
272a844f396SAlex Lorenz                               SourceSelectionKind::InsideSelection,
273a844f396SAlex Lorenz                               /*NumChildren=*/1);
27439265ca8SAlex Lorenz       });
275a844f396SAlex Lorenz }
276a844f396SAlex Lorenz 
277a844f396SAlex Lorenz TEST(ASTSelectionFinder, MultipleFunctionSelection) {
278a844f396SAlex Lorenz   StringRef Source = R"(void f0() {
279a844f396SAlex Lorenz }
280a844f396SAlex Lorenz void f1() { }
281a844f396SAlex Lorenz void f2() { }
282a844f396SAlex Lorenz void f3() { }
283a844f396SAlex Lorenz )";
2846ad0788cSKazu Hirata   auto SelectedF1F2 = [](std::optional<SelectedASTNode> Node) {
285a844f396SAlex Lorenz     EXPECT_TRUE(Node);
286a844f396SAlex Lorenz     EXPECT_EQ(Node->Children.size(), 2u);
287a844f396SAlex Lorenz     checkNode<FunctionDecl>(Node->Children[0],
288a844f396SAlex Lorenz                             SourceSelectionKind::InsideSelection,
289a844f396SAlex Lorenz                             /*NumChildren=*/1, /*Name=*/"f1");
290a844f396SAlex Lorenz     checkNode<FunctionDecl>(Node->Children[1],
291a844f396SAlex Lorenz                             SourceSelectionKind::InsideSelection,
292a844f396SAlex Lorenz                             /*NumChildren=*/1, /*Name=*/"f2");
293a844f396SAlex Lorenz   };
294a844f396SAlex Lorenz   // Just after '}' of f0 and just before 'void' of f3:
29539265ca8SAlex Lorenz   findSelectedASTNodes(Source, {2, 2}, FileRange{{2, 2}, {5, 1}}, SelectedF1F2);
296a844f396SAlex Lorenz   // Just before 'void' of f1 and just after '}' of f2:
29739265ca8SAlex Lorenz   findSelectedASTNodes(Source, {3, 1}, FileRange{{3, 1}, {4, 14}},
29839265ca8SAlex Lorenz                        SelectedF1F2);
299a844f396SAlex Lorenz }
300a844f396SAlex Lorenz 
301a844f396SAlex Lorenz TEST(ASTSelectionFinder, MultipleStatementSelection) {
302a844f396SAlex Lorenz   StringRef Source = R"(void f(int x, int y) {
303a844f396SAlex Lorenz   int z = x;
304a844f396SAlex Lorenz   f(2, 3);
305a844f396SAlex Lorenz   if (x == 0) {
306a844f396SAlex Lorenz     return;
307a844f396SAlex Lorenz   }
308a844f396SAlex Lorenz   x = 1;
309a844f396SAlex Lorenz   return;
310a844f396SAlex Lorenz })";
311a844f396SAlex Lorenz   // From 'f(2,3)' until just before 'x = 1;':
31239265ca8SAlex Lorenz   findSelectedASTNodes(
31339265ca8SAlex Lorenz       Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
3146ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
315a844f396SAlex Lorenz         EXPECT_TRUE(Node);
316a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
317a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
318a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
319a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"f");
320a844f396SAlex Lorenz         const auto &Body = checkNode<CompoundStmt>(
321a844f396SAlex Lorenz             Fn.Children[0], SourceSelectionKind::ContainsSelection,
322a844f396SAlex Lorenz             /*NumChildren=*/2);
323a844f396SAlex Lorenz         allChildrenOf(checkNode<CallExpr>(Body.Children[0],
324a844f396SAlex Lorenz                                           SourceSelectionKind::InsideSelection,
325a844f396SAlex Lorenz                                           /*NumChildren=*/3))
326a844f396SAlex Lorenz             .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
327a844f396SAlex Lorenz         allChildrenOf(checkNode<IfStmt>(Body.Children[1],
328a844f396SAlex Lorenz                                         SourceSelectionKind::InsideSelection,
329a844f396SAlex Lorenz                                         /*NumChildren=*/2))
330a844f396SAlex Lorenz             .shouldHaveSelectionKind(SourceSelectionKind::InsideSelection);
33139265ca8SAlex Lorenz       });
332a844f396SAlex Lorenz   // From 'f(2,3)' until just before ';' in 'x = 1;':
33339265ca8SAlex Lorenz   findSelectedASTNodes(
33439265ca8SAlex Lorenz       Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
3356ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
336a844f396SAlex Lorenz         EXPECT_TRUE(Node);
337a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
338a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
339a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
340a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"f");
341a844f396SAlex Lorenz         const auto &Body = checkNode<CompoundStmt>(
342a844f396SAlex Lorenz             Fn.Children[0], SourceSelectionKind::ContainsSelection,
343a844f396SAlex Lorenz             /*NumChildren=*/3);
34439265ca8SAlex Lorenz         checkNode<CallExpr>(Body.Children[0],
34539265ca8SAlex Lorenz                             SourceSelectionKind::InsideSelection,
346a844f396SAlex Lorenz                             /*NumChildren=*/3);
34739265ca8SAlex Lorenz         checkNode<IfStmt>(Body.Children[1],
34839265ca8SAlex Lorenz                           SourceSelectionKind::InsideSelection,
349a844f396SAlex Lorenz                           /*NumChildren=*/2);
350a844f396SAlex Lorenz         checkNode<BinaryOperator>(Body.Children[2],
351a844f396SAlex Lorenz                                   SourceSelectionKind::InsideSelection,
352a844f396SAlex Lorenz                                   /*NumChildren=*/2);
35339265ca8SAlex Lorenz       });
354a844f396SAlex Lorenz   // From the middle of 'int z = 3' until the middle of 'x = 1;':
35539265ca8SAlex Lorenz   findSelectedASTNodes(
35639265ca8SAlex Lorenz       Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
3576ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
358a844f396SAlex Lorenz         EXPECT_TRUE(Node);
359a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
360a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
361a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
362a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"f");
363a844f396SAlex Lorenz         const auto &Body = checkNode<CompoundStmt>(
364a844f396SAlex Lorenz             Fn.Children[0], SourceSelectionKind::ContainsSelection,
365a844f396SAlex Lorenz             /*NumChildren=*/4);
366a844f396SAlex Lorenz         checkNode<DeclStmt>(Body.Children[0],
367a844f396SAlex Lorenz                             SourceSelectionKind::ContainsSelectionStart,
368a844f396SAlex Lorenz                             /*NumChildren=*/1);
36939265ca8SAlex Lorenz         checkNode<CallExpr>(Body.Children[1],
37039265ca8SAlex Lorenz                             SourceSelectionKind::InsideSelection,
371a844f396SAlex Lorenz                             /*NumChildren=*/3);
37239265ca8SAlex Lorenz         checkNode<IfStmt>(Body.Children[2],
37339265ca8SAlex Lorenz                           SourceSelectionKind::InsideSelection,
374a844f396SAlex Lorenz                           /*NumChildren=*/2);
375a844f396SAlex Lorenz         checkNode<BinaryOperator>(Body.Children[3],
376a844f396SAlex Lorenz                                   SourceSelectionKind::ContainsSelectionEnd,
377a844f396SAlex Lorenz                                   /*NumChildren=*/1);
37839265ca8SAlex Lorenz       });
379a844f396SAlex Lorenz }
380a844f396SAlex Lorenz 
381a844f396SAlex Lorenz TEST(ASTSelectionFinder, SelectionInFunctionInObjCImplementation) {
382a844f396SAlex Lorenz   StringRef Source = R"(
383a844f396SAlex Lorenz @interface I
384a844f396SAlex Lorenz @end
385a844f396SAlex Lorenz @implementation I
386a844f396SAlex Lorenz 
387*12f78e74SSirraide int notSelected() { return 0; }
388a844f396SAlex Lorenz 
389a844f396SAlex Lorenz int selected(int x) {
390a844f396SAlex Lorenz   return x;
391a844f396SAlex Lorenz }
392a844f396SAlex Lorenz 
393a844f396SAlex Lorenz @end
394a844f396SAlex Lorenz @implementation I(Cat)
395a844f396SAlex Lorenz 
396a844f396SAlex Lorenz void catF() { }
397a844f396SAlex Lorenz 
398a844f396SAlex Lorenz @end
399a844f396SAlex Lorenz 
400a844f396SAlex Lorenz void outerFunction() { }
401a844f396SAlex Lorenz )";
402a844f396SAlex Lorenz   // Just the 'x' expression in 'selected':
40339265ca8SAlex Lorenz   findSelectedASTNodes(
40439265ca8SAlex Lorenz       Source, {9, 10}, FileRange{{9, 10}, {9, 11}},
4056ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
406a844f396SAlex Lorenz         EXPECT_TRUE(Node);
407a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
408a844f396SAlex Lorenz         const auto &Impl = checkNode<ObjCImplementationDecl>(
409a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
410a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"I");
411a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
412a844f396SAlex Lorenz             Impl.Children[0], SourceSelectionKind::ContainsSelection,
413a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"selected");
414a844f396SAlex Lorenz         allChildrenOf(Fn).shouldHaveSelectionKind(
415a844f396SAlex Lorenz             SourceSelectionKind::ContainsSelection);
41639265ca8SAlex Lorenz       },
417a844f396SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
41839265ca8SAlex Lorenz   // The entire 'catF':
41939265ca8SAlex Lorenz   findSelectedASTNodes(
42039265ca8SAlex Lorenz       Source, {15, 1}, FileRange{{15, 1}, {15, 16}},
4216ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
422a844f396SAlex Lorenz         EXPECT_TRUE(Node);
423a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
424a844f396SAlex Lorenz         const auto &Impl = checkNode<ObjCCategoryImplDecl>(
425a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
426a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"Cat");
427a844f396SAlex Lorenz         const auto &Fn = checkNode<FunctionDecl>(
428a844f396SAlex Lorenz             Impl.Children[0], SourceSelectionKind::ContainsSelection,
429a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"catF");
430a844f396SAlex Lorenz         allChildrenOf(Fn).shouldHaveSelectionKind(
431a844f396SAlex Lorenz             SourceSelectionKind::ContainsSelection);
43239265ca8SAlex Lorenz       },
433a844f396SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
43439265ca8SAlex Lorenz   // From the line before 'selected' to the line after 'catF':
43539265ca8SAlex Lorenz   findSelectedASTNodes(
43639265ca8SAlex Lorenz       Source, {16, 1}, FileRange{{7, 1}, {16, 1}},
4376ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
438a844f396SAlex Lorenz         EXPECT_TRUE(Node);
439a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 2u);
440a844f396SAlex Lorenz         const auto &Impl = checkNode<ObjCImplementationDecl>(
441a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelectionStart,
442a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"I");
443a844f396SAlex Lorenz         const auto &Selected = checkNode<FunctionDecl>(
444a844f396SAlex Lorenz             Impl.Children[0], SourceSelectionKind::InsideSelection,
445a844f396SAlex Lorenz             /*NumChildren=*/2, /*Name=*/"selected");
446a844f396SAlex Lorenz         allChildrenOf(Selected).shouldHaveSelectionKind(
447a844f396SAlex Lorenz             SourceSelectionKind::InsideSelection);
448a844f396SAlex Lorenz         const auto &Cat = checkNode<ObjCCategoryImplDecl>(
449a844f396SAlex Lorenz             Node->Children[1], SourceSelectionKind::ContainsSelectionEnd,
450a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"Cat");
451a844f396SAlex Lorenz         const auto &CatF = checkNode<FunctionDecl>(
452a844f396SAlex Lorenz             Cat.Children[0], SourceSelectionKind::InsideSelection,
453a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"catF");
454a844f396SAlex Lorenz         allChildrenOf(CatF).shouldHaveSelectionKind(
455a844f396SAlex Lorenz             SourceSelectionKind::InsideSelection);
45639265ca8SAlex Lorenz       },
457a844f396SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
45839265ca8SAlex Lorenz   // Just the 'outer' function:
4596ad0788cSKazu Hirata   findSelectedASTNodes(
4606ad0788cSKazu Hirata       Source, {19, 1}, FileRange{{19, 1}, {19, 25}},
4616ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
462a844f396SAlex Lorenz         EXPECT_TRUE(Node);
463a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
4646ad0788cSKazu Hirata         checkNode<FunctionDecl>(Node->Children[0],
465a844f396SAlex Lorenz                                 SourceSelectionKind::ContainsSelection,
466a844f396SAlex Lorenz                                 /*NumChildren=*/1, /*Name=*/"outerFunction");
46739265ca8SAlex Lorenz       },
46839265ca8SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
469a844f396SAlex Lorenz }
470a844f396SAlex Lorenz 
471a844f396SAlex Lorenz TEST(ASTSelectionFinder, FunctionInObjCImplementationCarefulWithEarlyExit) {
472a844f396SAlex Lorenz   StringRef Source = R"(
473a844f396SAlex Lorenz @interface I
474a844f396SAlex Lorenz @end
475a844f396SAlex Lorenz @implementation I
476a844f396SAlex Lorenz 
477a844f396SAlex Lorenz void selected() {
478a844f396SAlex Lorenz }
479a844f396SAlex Lorenz 
480a844f396SAlex Lorenz - (void) method { }
481a844f396SAlex Lorenz 
482a844f396SAlex Lorenz @end
483a844f396SAlex Lorenz )";
484a844f396SAlex Lorenz   // Just 'selected'
48539265ca8SAlex Lorenz   findSelectedASTNodes(
48639265ca8SAlex Lorenz       Source, {6, 1}, FileRange{{6, 1}, {7, 2}},
4876ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
488a844f396SAlex Lorenz         EXPECT_TRUE(Node);
489a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
490a844f396SAlex Lorenz         const auto &Impl = checkNode<ObjCImplementationDecl>(
491a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::ContainsSelection,
492a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"I");
493a844f396SAlex Lorenz         checkNode<FunctionDecl>(Impl.Children[0],
494a844f396SAlex Lorenz                                 SourceSelectionKind::ContainsSelection,
495a844f396SAlex Lorenz                                 /*NumChildren=*/1, /*Name=*/"selected");
49639265ca8SAlex Lorenz       },
49739265ca8SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
498a844f396SAlex Lorenz }
499a844f396SAlex Lorenz 
500a844f396SAlex Lorenz TEST(ASTSelectionFinder, AvoidImplicitDeclarations) {
501a844f396SAlex Lorenz   StringRef Source = R"(
502a844f396SAlex Lorenz struct Copy {
503a844f396SAlex Lorenz   int x;
504a844f396SAlex Lorenz };
505a844f396SAlex Lorenz void foo() {
506a844f396SAlex Lorenz   Copy x;
507a844f396SAlex Lorenz   Copy y = x;
508a844f396SAlex Lorenz }
509a844f396SAlex Lorenz )";
510a844f396SAlex Lorenz   // The entire struct 'Copy':
51139265ca8SAlex Lorenz   findSelectedASTNodes(
51239265ca8SAlex Lorenz       Source, {2, 1}, FileRange{{2, 1}, {4, 3}},
5136ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
514a844f396SAlex Lorenz         EXPECT_TRUE(Node);
515a844f396SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
516a844f396SAlex Lorenz         const auto &Record = checkNode<CXXRecordDecl>(
517a844f396SAlex Lorenz             Node->Children[0], SourceSelectionKind::InsideSelection,
518a844f396SAlex Lorenz             /*NumChildren=*/1, /*Name=*/"Copy");
519a844f396SAlex Lorenz         checkNode<FieldDecl>(Record.Children[0],
520a844f396SAlex Lorenz                              SourceSelectionKind::InsideSelection);
52139265ca8SAlex Lorenz       });
522a844f396SAlex Lorenz }
523a844f396SAlex Lorenz 
52423654b50SAlex Lorenz TEST(ASTSelectionFinder, CorrectEndForObjectiveCImplementation) {
52523654b50SAlex Lorenz   StringRef Source = R"(
52623654b50SAlex Lorenz @interface I
52723654b50SAlex Lorenz @end
52823654b50SAlex Lorenz @implementation I
52923654b50SAlex Lorenz @ end
53023654b50SAlex Lorenz )";
53123654b50SAlex Lorenz   // Just after '@ end'
532a41fbb1fSKazu Hirata   findSelectedASTNodes(
533a41fbb1fSKazu Hirata       Source, {5, 6}, std::nullopt,
5346ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
53523654b50SAlex Lorenz         EXPECT_TRUE(Node);
53623654b50SAlex Lorenz         EXPECT_EQ(Node->Children.size(), 1u);
53723654b50SAlex Lorenz         checkNode<ObjCImplementationDecl>(
538a41fbb1fSKazu Hirata             Node->Children[0], SourceSelectionKind::ContainsSelection);
53923654b50SAlex Lorenz       },
54023654b50SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
54123654b50SAlex Lorenz }
54223654b50SAlex Lorenz 
5436ad0788cSKazu Hirata const SelectedASTNode &checkFnBody(const std::optional<SelectedASTNode> &Node,
544410ef383SAlex Lorenz                                    StringRef Name) {
545410ef383SAlex Lorenz   EXPECT_TRUE(Node);
546410ef383SAlex Lorenz   EXPECT_EQ(Node->Children.size(), 1u);
547410ef383SAlex Lorenz   const auto &Fn = checkNode<FunctionDecl>(
548410ef383SAlex Lorenz       Node->Children[0], SourceSelectionKind::ContainsSelection,
549410ef383SAlex Lorenz       /*NumChildren=*/1, Name);
550410ef383SAlex Lorenz   return checkNode<CompoundStmt>(Fn.Children[0],
551410ef383SAlex Lorenz                                  SourceSelectionKind::ContainsSelection,
552410ef383SAlex Lorenz                                  /*NumChildren=*/1);
553410ef383SAlex Lorenz }
554410ef383SAlex Lorenz 
555410ef383SAlex Lorenz TEST(ASTSelectionFinder, SelectObjectiveCPseudoObjectExprs) {
556410ef383SAlex Lorenz   StringRef Source = R"(
557410ef383SAlex Lorenz @interface I
558410ef383SAlex Lorenz @property(readwrite) int prop;
559410ef383SAlex Lorenz @end
560410ef383SAlex Lorenz void selectProp(I *i) {
561410ef383SAlex Lorenz (void)i.prop;
562410ef383SAlex Lorenz i.prop = 21;
563410ef383SAlex Lorenz }
564410ef383SAlex Lorenz 
565caf2ef0dSAlex Lorenz 
566410ef383SAlex Lorenz @interface NSMutableArray
567caf2ef0dSAlex Lorenz - (id)objectAtIndexedSubscript:(unsigned int)index;
568caf2ef0dSAlex Lorenz - (void)setObject:(id)object atIndexedSubscript:(unsigned int)index;
569410ef383SAlex Lorenz @end
570410ef383SAlex Lorenz 
571410ef383SAlex Lorenz void selectSubscript(NSMutableArray *array, I *i) {
572410ef383SAlex Lorenz   (void)array[10];
573410ef383SAlex Lorenz   array[i.prop] = i;
574410ef383SAlex Lorenz }
575410ef383SAlex Lorenz )";
576410ef383SAlex Lorenz   // Just 'i.prop'.
577410ef383SAlex Lorenz   findSelectedASTNodes(
578410ef383SAlex Lorenz       Source, {6, 7}, FileRange{{6, 7}, {6, 13}},
5796ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
580410ef383SAlex Lorenz         const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
581410ef383SAlex Lorenz         const auto &CCast = checkNode<CStyleCastExpr>(
582410ef383SAlex Lorenz             CS.Children[0], SourceSelectionKind::ContainsSelection,
583410ef383SAlex Lorenz             /*NumChildren=*/1);
584410ef383SAlex Lorenz         const auto &POE = checkNode<PseudoObjectExpr>(
585410ef383SAlex Lorenz             CCast.Children[0], SourceSelectionKind::ContainsSelection,
586410ef383SAlex Lorenz             /*NumChildren=*/1);
587410ef383SAlex Lorenz         const auto &PRE = checkNode<ObjCPropertyRefExpr>(
588410ef383SAlex Lorenz             POE.Children[0], SourceSelectionKind::ContainsSelection,
589410ef383SAlex Lorenz             /*NumChildren=*/1);
590410ef383SAlex Lorenz         const auto &Cast = checkNode<ImplicitCastExpr>(
591410ef383SAlex Lorenz             PRE.Children[0], SourceSelectionKind::InsideSelection,
592410ef383SAlex Lorenz             /*NumChildren=*/1);
593410ef383SAlex Lorenz         checkNode<DeclRefExpr>(Cast.Children[0],
594410ef383SAlex Lorenz                                SourceSelectionKind::InsideSelection);
595410ef383SAlex Lorenz       },
596410ef383SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
597410ef383SAlex Lorenz   // Just 'i.prop = 21'
598410ef383SAlex Lorenz   findSelectedASTNodes(
599410ef383SAlex Lorenz       Source, {7, 1}, FileRange{{7, 1}, {7, 12}},
6006ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
601410ef383SAlex Lorenz         const auto &CS = checkFnBody(Node, /*Name=*/"selectProp");
602410ef383SAlex Lorenz         const auto &POE = checkNode<PseudoObjectExpr>(
603410ef383SAlex Lorenz             CS.Children[0], SourceSelectionKind::ContainsSelection,
604410ef383SAlex Lorenz             /*NumChildren=*/1);
605410ef383SAlex Lorenz         const auto &BinOp = checkNode<BinaryOperator>(
606410ef383SAlex Lorenz             POE.Children[0], SourceSelectionKind::ContainsSelection,
607410ef383SAlex Lorenz             /*NumChildren=*/2);
608410ef383SAlex Lorenz         const auto &PRE = checkNode<ObjCPropertyRefExpr>(
609410ef383SAlex Lorenz             BinOp.Children[0], SourceSelectionKind::InsideSelection,
610410ef383SAlex Lorenz             /*NumChildren=*/1);
611410ef383SAlex Lorenz         const auto &Cast = checkNode<ImplicitCastExpr>(
612410ef383SAlex Lorenz             PRE.Children[0], SourceSelectionKind::InsideSelection,
613410ef383SAlex Lorenz             /*NumChildren=*/1);
614410ef383SAlex Lorenz         checkNode<DeclRefExpr>(Cast.Children[0],
615410ef383SAlex Lorenz                                SourceSelectionKind::InsideSelection);
616410ef383SAlex Lorenz         checkNode<IntegerLiteral>(BinOp.Children[1],
617410ef383SAlex Lorenz                                   SourceSelectionKind::InsideSelection);
618410ef383SAlex Lorenz       },
619410ef383SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
620410ef383SAlex Lorenz   // Just 'array[10]'
621410ef383SAlex Lorenz   findSelectedASTNodes(
622410ef383SAlex Lorenz       Source, {17, 9}, FileRange{{17, 9}, {17, 18}},
6236ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
624410ef383SAlex Lorenz         const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
625410ef383SAlex Lorenz         const auto &CCast = checkNode<CStyleCastExpr>(
626410ef383SAlex Lorenz             CS.Children[0], SourceSelectionKind::ContainsSelection,
627410ef383SAlex Lorenz             /*NumChildren=*/1);
628410ef383SAlex Lorenz         const auto &POE = checkNode<PseudoObjectExpr>(
629410ef383SAlex Lorenz             CCast.Children[0], SourceSelectionKind::ContainsSelection,
630410ef383SAlex Lorenz             /*NumChildren=*/1);
631410ef383SAlex Lorenz         const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
632410ef383SAlex Lorenz             POE.Children[0], SourceSelectionKind::ContainsSelection,
633410ef383SAlex Lorenz             /*NumChildren=*/2);
634410ef383SAlex Lorenz         const auto &Cast = checkNode<ImplicitCastExpr>(
635410ef383SAlex Lorenz             SRE.Children[0], SourceSelectionKind::InsideSelection,
636410ef383SAlex Lorenz             /*NumChildren=*/1);
637410ef383SAlex Lorenz         checkNode<DeclRefExpr>(Cast.Children[0],
638410ef383SAlex Lorenz                                SourceSelectionKind::InsideSelection);
639410ef383SAlex Lorenz         checkNode<IntegerLiteral>(SRE.Children[1],
640410ef383SAlex Lorenz                                   SourceSelectionKind::InsideSelection);
641410ef383SAlex Lorenz       },
642410ef383SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
643410ef383SAlex Lorenz   // Just 'array[i.prop] = array'
644410ef383SAlex Lorenz   findSelectedASTNodes(
645410ef383SAlex Lorenz       Source, {18, 3}, FileRange{{18, 3}, {18, 20}},
6466ad0788cSKazu Hirata       [](std::optional<SelectedASTNode> Node) {
647410ef383SAlex Lorenz         const auto &CS = checkFnBody(Node, /*Name=*/"selectSubscript");
648410ef383SAlex Lorenz         const auto &POE = checkNode<PseudoObjectExpr>(
649410ef383SAlex Lorenz             CS.Children[0], SourceSelectionKind::ContainsSelection,
650410ef383SAlex Lorenz             /*NumChildren=*/1);
651410ef383SAlex Lorenz         const auto &BinOp = checkNode<BinaryOperator>(
652410ef383SAlex Lorenz             POE.Children[0], SourceSelectionKind::ContainsSelection,
653410ef383SAlex Lorenz             /*NumChildren=*/2);
654410ef383SAlex Lorenz         const auto &SRE = checkNode<ObjCSubscriptRefExpr>(
655410ef383SAlex Lorenz             BinOp.Children[0], SourceSelectionKind::InsideSelection,
656410ef383SAlex Lorenz             /*NumChildren=*/2);
657410ef383SAlex Lorenz         const auto &Cast = checkNode<ImplicitCastExpr>(
658410ef383SAlex Lorenz             SRE.Children[0], SourceSelectionKind::InsideSelection,
659410ef383SAlex Lorenz             /*NumChildren=*/1);
660410ef383SAlex Lorenz         checkNode<DeclRefExpr>(Cast.Children[0],
661410ef383SAlex Lorenz                                SourceSelectionKind::InsideSelection);
662410ef383SAlex Lorenz         const auto &POE2 = checkNode<PseudoObjectExpr>(
663410ef383SAlex Lorenz             SRE.Children[1], SourceSelectionKind::InsideSelection,
664410ef383SAlex Lorenz             /*NumChildren=*/1);
665410ef383SAlex Lorenz         const auto &PRE = checkNode<ObjCPropertyRefExpr>(
666410ef383SAlex Lorenz             POE2.Children[0], SourceSelectionKind::InsideSelection,
667410ef383SAlex Lorenz             /*NumChildren=*/1);
668410ef383SAlex Lorenz         const auto &Cast2 = checkNode<ImplicitCastExpr>(
669410ef383SAlex Lorenz             PRE.Children[0], SourceSelectionKind::InsideSelection,
670410ef383SAlex Lorenz             /*NumChildren=*/1);
671410ef383SAlex Lorenz         checkNode<DeclRefExpr>(Cast2.Children[0],
672410ef383SAlex Lorenz                                SourceSelectionKind::InsideSelection);
673410ef383SAlex Lorenz         checkNode<DeclRefExpr>(BinOp.Children[1],
674410ef383SAlex Lorenz                                SourceSelectionKind::InsideSelection);
675410ef383SAlex Lorenz       },
676410ef383SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
677410ef383SAlex Lorenz }
678410ef383SAlex Lorenz 
679cd6c7838SAlex Lorenz TEST(ASTSelectionFinder, SimpleCodeRangeASTSelection) {
680cd6c7838SAlex Lorenz   StringRef Source = R"(void f(int x, int y) {
681cd6c7838SAlex Lorenz   int z = x;
682cd6c7838SAlex Lorenz   f(2, 3);
683cd6c7838SAlex Lorenz   if (x == 0) {
684cd6c7838SAlex Lorenz     return;
685cd6c7838SAlex Lorenz   }
686cd6c7838SAlex Lorenz   x = 1;
687cd6c7838SAlex Lorenz   return;
688cd6c7838SAlex Lorenz }
689cd6c7838SAlex Lorenz void f2() {
690cd6c7838SAlex Lorenz   int m = 0;
691cd6c7838SAlex Lorenz }
692cd6c7838SAlex Lorenz )";
693cd6c7838SAlex Lorenz   // No selection range.
694cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
695a41fbb1fSKazu Hirata       Source, {2, 2}, std::nullopt,
6966ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
697cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
6986ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
699cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
700cd6c7838SAlex Lorenz         EXPECT_FALSE(SelectedCode);
701cd6c7838SAlex Lorenz       });
702cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
703cd6c7838SAlex Lorenz       Source, {2, 2}, FileRange{{2, 2}, {2, 2}},
7046ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
705cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
7066ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
707cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
708cd6c7838SAlex Lorenz         EXPECT_FALSE(SelectedCode);
709cd6c7838SAlex Lorenz       });
710cd6c7838SAlex Lorenz   // Range that spans multiple functions is an invalid code range.
711cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
712cd6c7838SAlex Lorenz       Source, {2, 2}, FileRange{{7, 2}, {12, 1}},
7136ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
714cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
7156ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
716cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
717cd6c7838SAlex Lorenz         EXPECT_FALSE(SelectedCode);
718cd6c7838SAlex Lorenz       });
719cd6c7838SAlex Lorenz   // Just 'z = x;':
720cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
721cd6c7838SAlex Lorenz       Source, {2, 2}, FileRange{{2, 2}, {2, 13}},
7226ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
723cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
7246ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
725cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
726cd6c7838SAlex Lorenz         EXPECT_TRUE(SelectedCode);
727cd6c7838SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
728cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
729cd6c7838SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
730cd6c7838SAlex Lorenz             SelectedCode->getParents();
731cd6c7838SAlex Lorenz         EXPECT_EQ(Parents.size(), 3u);
732cd6c7838SAlex Lorenz         EXPECT_TRUE(
733cd6c7838SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
734cd6c7838SAlex Lorenz         // Function 'f' definition.
735cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
736cd6c7838SAlex Lorenz         // Function body of function 'F'.
737cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
738cd6c7838SAlex Lorenz       });
739cd6c7838SAlex Lorenz   // From 'f(2,3)' until just before 'x = 1;':
740cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
741cd6c7838SAlex Lorenz       Source, {3, 2}, FileRange{{3, 2}, {7, 1}},
7426ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
743cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
7446ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
745cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
746cd6c7838SAlex Lorenz         EXPECT_TRUE(SelectedCode);
747cd6c7838SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 2u);
748cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
749cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
750cd6c7838SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
751cd6c7838SAlex Lorenz             SelectedCode->getParents();
752cd6c7838SAlex Lorenz         EXPECT_EQ(Parents.size(), 3u);
753cd6c7838SAlex Lorenz         EXPECT_TRUE(
754cd6c7838SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
755cd6c7838SAlex Lorenz         // Function 'f' definition.
756cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
757cd6c7838SAlex Lorenz         // Function body of function 'F'.
758cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
759cd6c7838SAlex Lorenz       });
760cd6c7838SAlex Lorenz   // From 'f(2,3)' until just before ';' in 'x = 1;':
761cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
762cd6c7838SAlex Lorenz       Source, {3, 2}, FileRange{{3, 2}, {7, 8}},
7636ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
764cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
7656ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
766cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
767cd6c7838SAlex Lorenz         EXPECT_TRUE(SelectedCode);
768cd6c7838SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 3u);
769cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
770cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
771cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[2]));
772cd6c7838SAlex Lorenz       });
773cd6c7838SAlex Lorenz   // From the middle of 'int z = 3' until the middle of 'x = 1;':
774cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
775cd6c7838SAlex Lorenz       Source, {2, 10}, FileRange{{2, 10}, {7, 5}},
7766ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
777cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
778cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
7796ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
780cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
781cd6c7838SAlex Lorenz         EXPECT_TRUE(SelectedCode);
782cd6c7838SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 4u);
783cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
784cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[1]));
785cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[2]));
786cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[3]));
787cd6c7838SAlex Lorenz       });
788cd6c7838SAlex Lorenz }
789cd6c7838SAlex Lorenz 
790cd6c7838SAlex Lorenz TEST(ASTSelectionFinder, OutOfBodyCodeRange) {
791cd6c7838SAlex Lorenz   StringRef Source = R"(
792cd6c7838SAlex Lorenz int codeRange = 2 + 3;
793cd6c7838SAlex Lorenz )";
794cd6c7838SAlex Lorenz   // '2+3' expression.
795cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
796cd6c7838SAlex Lorenz       Source, {2, 17}, FileRange{{2, 17}, {2, 22}},
7976ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
798cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
7996ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
800cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
801cd6c7838SAlex Lorenz         EXPECT_TRUE(SelectedCode);
802cd6c7838SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
803cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<BinaryOperator>((*SelectedCode)[0]));
804cd6c7838SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
805cd6c7838SAlex Lorenz             SelectedCode->getParents();
806cd6c7838SAlex Lorenz         EXPECT_EQ(Parents.size(), 2u);
807cd6c7838SAlex Lorenz         EXPECT_TRUE(
808cd6c7838SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
809cd6c7838SAlex Lorenz         // Variable 'codeRange'.
810cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<VarDecl>(Parents[1].get().Node.get<Decl>()));
811cd6c7838SAlex Lorenz       });
812cd6c7838SAlex Lorenz }
813cd6c7838SAlex Lorenz 
814cd6c7838SAlex Lorenz TEST(ASTSelectionFinder, SelectVarDeclStmt) {
815cd6c7838SAlex Lorenz   StringRef Source = R"(
816cd6c7838SAlex Lorenz void f() {
817cd6c7838SAlex Lorenz    {
818cd6c7838SAlex Lorenz        int a;
819cd6c7838SAlex Lorenz    }
820cd6c7838SAlex Lorenz }
821cd6c7838SAlex Lorenz )";
822cd6c7838SAlex Lorenz   // 'int a'
823cd6c7838SAlex Lorenz   findSelectedASTNodesWithRange(
824cd6c7838SAlex Lorenz       Source, {4, 8}, FileRange{{4, 8}, {4, 14}},
8256ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
826cd6c7838SAlex Lorenz         EXPECT_TRUE(Node);
8276ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
828cd6c7838SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
829cd6c7838SAlex Lorenz         EXPECT_TRUE(SelectedCode);
830cd6c7838SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
831cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
832cd6c7838SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
833cd6c7838SAlex Lorenz             SelectedCode->getParents();
834cd6c7838SAlex Lorenz         EXPECT_EQ(Parents.size(), 4u);
835cd6c7838SAlex Lorenz         EXPECT_TRUE(
836cd6c7838SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
837cd6c7838SAlex Lorenz         // Function 'f' definition.
838cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
839cd6c7838SAlex Lorenz         // Function body of function 'F'.
840cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
841cd6c7838SAlex Lorenz         // Compound statement in body of 'F'.
842cd6c7838SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
843cd6c7838SAlex Lorenz       });
844cd6c7838SAlex Lorenz }
845cd6c7838SAlex Lorenz 
846b87b6bf7SAlex Lorenz TEST(ASTSelectionFinder, SelectEntireDeclStmtRange) {
847b87b6bf7SAlex Lorenz   StringRef Source = R"(
848b87b6bf7SAlex Lorenz void f(int x, int y) {
849b87b6bf7SAlex Lorenz    int a = x * y;
850b87b6bf7SAlex Lorenz }
851b87b6bf7SAlex Lorenz )";
852b87b6bf7SAlex Lorenz   // 'int a = x * y'
853b87b6bf7SAlex Lorenz   findSelectedASTNodesWithRange(
854b87b6bf7SAlex Lorenz       Source, {3, 4}, FileRange{{3, 4}, {3, 17}},
8556ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
856b87b6bf7SAlex Lorenz         EXPECT_TRUE(Node);
8576ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
858b87b6bf7SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
859b87b6bf7SAlex Lorenz         EXPECT_TRUE(SelectedCode);
860b87b6bf7SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
861b87b6bf7SAlex Lorenz         EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
862b87b6bf7SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
863b87b6bf7SAlex Lorenz             SelectedCode->getParents();
864b87b6bf7SAlex Lorenz         EXPECT_EQ(Parents.size(), 3u);
865b87b6bf7SAlex Lorenz         EXPECT_TRUE(
866b87b6bf7SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
867b87b6bf7SAlex Lorenz         // Function 'f' definition.
868b87b6bf7SAlex Lorenz         EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
869b87b6bf7SAlex Lorenz         // Function body of function 'F'.
870b87b6bf7SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
871b87b6bf7SAlex Lorenz       });
872b87b6bf7SAlex Lorenz }
873b87b6bf7SAlex Lorenz 
874b87b6bf7SAlex Lorenz TEST(ASTSelectionFinder, SelectEntireDeclStmtRangeWithMultipleDecls) {
875b87b6bf7SAlex Lorenz   StringRef Source = R"(
876b87b6bf7SAlex Lorenz void f(int x, int y) {
877b87b6bf7SAlex Lorenz    int a = x * y, b = x - y;
878b87b6bf7SAlex Lorenz }
879b87b6bf7SAlex Lorenz )";
880b87b6bf7SAlex Lorenz   // 'b = x - y'
881b87b6bf7SAlex Lorenz   findSelectedASTNodesWithRange(
882b87b6bf7SAlex Lorenz       Source, {3, 19}, FileRange{{3, 19}, {3, 28}},
8836ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
884b87b6bf7SAlex Lorenz         EXPECT_TRUE(Node);
8856ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
886b87b6bf7SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
887b87b6bf7SAlex Lorenz         EXPECT_TRUE(SelectedCode);
888b87b6bf7SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
889b87b6bf7SAlex Lorenz         EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
890b87b6bf7SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
891b87b6bf7SAlex Lorenz             SelectedCode->getParents();
892b87b6bf7SAlex Lorenz         EXPECT_EQ(Parents.size(), 3u);
893b87b6bf7SAlex Lorenz         EXPECT_TRUE(
894b87b6bf7SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
895b87b6bf7SAlex Lorenz         // Function 'f' definition.
896b87b6bf7SAlex Lorenz         EXPECT_TRUE(isa<FunctionDecl>(Parents[1].get().Node.get<Decl>()));
897b87b6bf7SAlex Lorenz         // Function body of function 'F'.
898b87b6bf7SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[2].get().Node.get<Stmt>()));
899b87b6bf7SAlex Lorenz       });
900b87b6bf7SAlex Lorenz }
901b87b6bf7SAlex Lorenz 
9027cd48cd8SAlex Lorenz TEST(ASTSelectionFinder, SimpleCodeRangeASTSelectionInObjCMethod) {
9037cd48cd8SAlex Lorenz   StringRef Source = R"(@interface I @end
9047cd48cd8SAlex Lorenz @implementation I
9057cd48cd8SAlex Lorenz - (void) f:(int)x with:(int) y {
9067cd48cd8SAlex Lorenz   int z = x;
9077cd48cd8SAlex Lorenz   [self f: 2 with: 3];
9087cd48cd8SAlex Lorenz   if (x == 0) {
9097cd48cd8SAlex Lorenz     return;
9107cd48cd8SAlex Lorenz   }
9117cd48cd8SAlex Lorenz   x = 1;
9127cd48cd8SAlex Lorenz   return;
9137cd48cd8SAlex Lorenz }
9147cd48cd8SAlex Lorenz - (void)f2 {
9157cd48cd8SAlex Lorenz   int m = 0;
9167cd48cd8SAlex Lorenz }
9177cd48cd8SAlex Lorenz @end
9187cd48cd8SAlex Lorenz )";
9197cd48cd8SAlex Lorenz   // Range that spans multiple methods is an invalid code range.
9207cd48cd8SAlex Lorenz   findSelectedASTNodesWithRange(
9217cd48cd8SAlex Lorenz       Source, {9, 2}, FileRange{{9, 2}, {13, 1}},
9226ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
9237cd48cd8SAlex Lorenz         EXPECT_TRUE(Node);
9246ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
9257cd48cd8SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
9267cd48cd8SAlex Lorenz         EXPECT_FALSE(SelectedCode);
9277cd48cd8SAlex Lorenz       },
9287cd48cd8SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
9297cd48cd8SAlex Lorenz   // Just 'z = x;':
9307cd48cd8SAlex Lorenz   findSelectedASTNodesWithRange(
9317cd48cd8SAlex Lorenz       Source, {4, 2}, FileRange{{4, 2}, {4, 13}},
9326ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
9337cd48cd8SAlex Lorenz         EXPECT_TRUE(Node);
9346ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
9357cd48cd8SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
9367cd48cd8SAlex Lorenz         EXPECT_TRUE(SelectedCode);
9377cd48cd8SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
9387cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<DeclStmt>((*SelectedCode)[0]));
9397cd48cd8SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
9407cd48cd8SAlex Lorenz             SelectedCode->getParents();
9417cd48cd8SAlex Lorenz         EXPECT_EQ(Parents.size(), 4u);
9427cd48cd8SAlex Lorenz         EXPECT_TRUE(
9437cd48cd8SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
9447cd48cd8SAlex Lorenz         // 'I' @implementation.
9457cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
9467cd48cd8SAlex Lorenz         // Function 'f' definition.
9477cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
9487cd48cd8SAlex Lorenz         // Function body of function 'F'.
9497cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
9507cd48cd8SAlex Lorenz       },
9517cd48cd8SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
9527cd48cd8SAlex Lorenz   // From '[self f: 2 with: 3]' until just before 'x = 1;':
9537cd48cd8SAlex Lorenz   findSelectedASTNodesWithRange(
9547cd48cd8SAlex Lorenz       Source, {5, 2}, FileRange{{5, 2}, {9, 1}},
9556ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
9567cd48cd8SAlex Lorenz         EXPECT_TRUE(Node);
9576ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
9587cd48cd8SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
9597cd48cd8SAlex Lorenz         EXPECT_TRUE(SelectedCode);
9607cd48cd8SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 2u);
9617cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<ObjCMessageExpr>((*SelectedCode)[0]));
9627cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<IfStmt>((*SelectedCode)[1]));
9637cd48cd8SAlex Lorenz         ArrayRef<SelectedASTNode::ReferenceType> Parents =
9647cd48cd8SAlex Lorenz             SelectedCode->getParents();
9657cd48cd8SAlex Lorenz         EXPECT_EQ(Parents.size(), 4u);
9667cd48cd8SAlex Lorenz         EXPECT_TRUE(
9677cd48cd8SAlex Lorenz             isa<TranslationUnitDecl>(Parents[0].get().Node.get<Decl>()));
9687cd48cd8SAlex Lorenz         // 'I' @implementation.
9697cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<ObjCImplDecl>(Parents[1].get().Node.get<Decl>()));
9707cd48cd8SAlex Lorenz         // Function 'f' definition.
9717cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<ObjCMethodDecl>(Parents[2].get().Node.get<Decl>()));
9727cd48cd8SAlex Lorenz         // Function body of function 'F'.
9737cd48cd8SAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(Parents[3].get().Node.get<Stmt>()));
9747cd48cd8SAlex Lorenz       },
9757cd48cd8SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
9767cd48cd8SAlex Lorenz }
9777cd48cd8SAlex Lorenz 
978547e5ad0SAlex Lorenz TEST(ASTSelectionFinder, CanonicalizeObjCStringLiteral) {
979547e5ad0SAlex Lorenz   StringRef Source = R"(
980547e5ad0SAlex Lorenz void foo() {
981547e5ad0SAlex Lorenz   (void)@"test";
982547e5ad0SAlex Lorenz }
983547e5ad0SAlex Lorenz       )";
984547e5ad0SAlex Lorenz   // Just '"test"':
985547e5ad0SAlex Lorenz   findSelectedASTNodesWithRange(
986547e5ad0SAlex Lorenz       Source, {3, 10}, FileRange{{3, 10}, {3, 16}},
9876ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
988547e5ad0SAlex Lorenz         EXPECT_TRUE(Node);
9896ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
990547e5ad0SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
991547e5ad0SAlex Lorenz         EXPECT_TRUE(SelectedCode);
992547e5ad0SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
993547e5ad0SAlex Lorenz         EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
994547e5ad0SAlex Lorenz       },
995547e5ad0SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
996547e5ad0SAlex Lorenz   // Just 'test':
997547e5ad0SAlex Lorenz   findSelectedASTNodesWithRange(
998547e5ad0SAlex Lorenz       Source, {3, 11}, FileRange{{3, 11}, {3, 15}},
9996ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1000547e5ad0SAlex Lorenz         EXPECT_TRUE(Node);
10016ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
1002547e5ad0SAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1003547e5ad0SAlex Lorenz         EXPECT_TRUE(SelectedCode);
1004547e5ad0SAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
1005547e5ad0SAlex Lorenz         EXPECT_TRUE(isa<ObjCStringLiteral>((*SelectedCode)[0]));
1006547e5ad0SAlex Lorenz       },
1007547e5ad0SAlex Lorenz       SelectionFinderVisitor::Lang_OBJC);
1008547e5ad0SAlex Lorenz }
1009547e5ad0SAlex Lorenz 
1010f64d0a4dSAlex Lorenz TEST(ASTSelectionFinder, CanonicalizeMemberCalleeToCall) {
1011f64d0a4dSAlex Lorenz   StringRef Source = R"(
1012f64d0a4dSAlex Lorenz class AClass { public:
1013f64d0a4dSAlex Lorenz   void method();
1014f64d0a4dSAlex Lorenz   int afield;
1015f64d0a4dSAlex Lorenz   void selectWholeCallWhenJustMethodSelected(int &i) {
1016f64d0a4dSAlex Lorenz     method();
1017f64d0a4dSAlex Lorenz   }
1018f64d0a4dSAlex Lorenz };
1019f64d0a4dSAlex Lorenz void selectWholeCallWhenJustMethodSelected() {
1020f64d0a4dSAlex Lorenz   AClass a;
1021f64d0a4dSAlex Lorenz   a.method();
1022f64d0a4dSAlex Lorenz }
1023f64d0a4dSAlex Lorenz void dontSelectArgument(AClass &a) {
1024f64d0a4dSAlex Lorenz   a.selectWholeCallWhenJustMethodSelected(a.afield);
1025f64d0a4dSAlex Lorenz }
1026f64d0a4dSAlex Lorenz      )";
1027f64d0a4dSAlex Lorenz   // Just 'method' with implicit 'this':
1028f64d0a4dSAlex Lorenz   findSelectedASTNodesWithRange(
1029f64d0a4dSAlex Lorenz       Source, {6, 5}, FileRange{{6, 5}, {6, 11}},
10306ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1031f64d0a4dSAlex Lorenz         EXPECT_TRUE(Node);
10326ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
1033f64d0a4dSAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1034f64d0a4dSAlex Lorenz         EXPECT_TRUE(SelectedCode);
1035f64d0a4dSAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
1036f64d0a4dSAlex Lorenz         EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1037f64d0a4dSAlex Lorenz       });
1038f64d0a4dSAlex Lorenz   // Just 'method':
1039f64d0a4dSAlex Lorenz   findSelectedASTNodesWithRange(
1040f64d0a4dSAlex Lorenz       Source, {11, 5}, FileRange{{11, 5}, {11, 11}},
10416ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1042f64d0a4dSAlex Lorenz         EXPECT_TRUE(Node);
10436ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
1044f64d0a4dSAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1045f64d0a4dSAlex Lorenz         EXPECT_TRUE(SelectedCode);
1046f64d0a4dSAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
1047f64d0a4dSAlex Lorenz         EXPECT_TRUE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1048f64d0a4dSAlex Lorenz       });
1049f64d0a4dSAlex Lorenz   // Just 'afield', which should not select the call.
1050f64d0a4dSAlex Lorenz   findSelectedASTNodesWithRange(
1051f64d0a4dSAlex Lorenz       Source, {14, 5}, FileRange{{14, 45}, {14, 51}},
10526ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
1053f64d0a4dSAlex Lorenz         EXPECT_TRUE(Node);
10546ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
1055f64d0a4dSAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
1056f64d0a4dSAlex Lorenz         EXPECT_TRUE(SelectedCode);
1057f64d0a4dSAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
1058f64d0a4dSAlex Lorenz         EXPECT_FALSE(isa<CXXMemberCallExpr>((*SelectedCode)[0]));
1059f64d0a4dSAlex Lorenz       });
1060f64d0a4dSAlex Lorenz }
1061f64d0a4dSAlex Lorenz 
10628337f81fSAlex Lorenz TEST(ASTSelectionFinder, CanonicalizeFuncCalleeToCall) {
10638337f81fSAlex Lorenz   StringRef Source = R"(
10648337f81fSAlex Lorenz void function();
10658337f81fSAlex Lorenz 
10668337f81fSAlex Lorenz void test() {
10678337f81fSAlex Lorenz   function();
10688337f81fSAlex Lorenz }
10698337f81fSAlex Lorenz      )";
10708337f81fSAlex Lorenz   // Just 'function':
10718337f81fSAlex Lorenz   findSelectedASTNodesWithRange(
10728337f81fSAlex Lorenz       Source, {5, 3}, FileRange{{5, 3}, {5, 11}},
10736ad0788cSKazu Hirata       [](SourceRange SelectionRange, std::optional<SelectedASTNode> Node) {
10748337f81fSAlex Lorenz         EXPECT_TRUE(Node);
10758337f81fSAlex Lorenz         Node->dump();
10766ad0788cSKazu Hirata         std::optional<CodeRangeASTSelection> SelectedCode =
10778337f81fSAlex Lorenz             CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
10788337f81fSAlex Lorenz         EXPECT_TRUE(SelectedCode);
10798337f81fSAlex Lorenz         EXPECT_EQ(SelectedCode->size(), 1u);
10808337f81fSAlex Lorenz         EXPECT_TRUE(isa<CallExpr>((*SelectedCode)[0]));
10818337f81fSAlex Lorenz         EXPECT_TRUE(isa<CompoundStmt>(
10828337f81fSAlex Lorenz             SelectedCode->getParents()[SelectedCode->getParents().size() - 1]
10838337f81fSAlex Lorenz                 .get()
10848337f81fSAlex Lorenz                 .Node.get<Stmt>()));
10858337f81fSAlex Lorenz       });
10868337f81fSAlex Lorenz }
10878337f81fSAlex Lorenz 
1088a844f396SAlex Lorenz } // end anonymous namespace
1089