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