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