ASTSelectionTest.cpp 42 KB

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