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