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