RangeSelectorTest.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. //===- unittest/Tooling/RangeSelectorTest.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 "clang/Tooling/Transformer/RangeSelector.h"
  9. #include "clang/ASTMatchers/ASTMatchers.h"
  10. #include "clang/Frontend/ASTUnit.h"
  11. #include "clang/Tooling/Tooling.h"
  12. #include "clang/Tooling/Transformer/SourceCode.h"
  13. #include "llvm/Support/Error.h"
  14. #include "llvm/Testing/Support/Error.h"
  15. #include "gmock/gmock.h"
  16. #include "gtest/gtest.h"
  17. using namespace clang;
  18. using namespace transformer;
  19. using namespace ast_matchers;
  20. namespace {
  21. using ::llvm::Expected;
  22. using ::llvm::Failed;
  23. using ::llvm::HasValue;
  24. using ::llvm::StringError;
  25. using ::testing::AllOf;
  26. using ::testing::HasSubstr;
  27. using ::testing::Property;
  28. using MatchResult = MatchFinder::MatchResult;
  29. struct TestMatch {
  30. // The AST unit from which `result` is built. We bundle it because it backs
  31. // the result. Users are not expected to access it.
  32. std::unique_ptr<clang::ASTUnit> ASTUnit;
  33. // The result to use in the test. References `ast_unit`.
  34. MatchResult Result;
  35. };
  36. template <typename M> TestMatch matchCode(StringRef Code, M Matcher) {
  37. auto ASTUnit = tooling::buildASTFromCode(Code);
  38. assert(ASTUnit != nullptr && "AST construction failed");
  39. ASTContext &Context = ASTUnit->getASTContext();
  40. assert(!Context.getDiagnostics().hasErrorOccurred() && "Compilation error");
  41. auto Matches = ast_matchers::match(Matcher, Context);
  42. // We expect a single, exact match.
  43. assert(Matches.size() != 0 && "no matches found");
  44. assert(Matches.size() == 1 && "too many matches");
  45. return TestMatch{std::move(ASTUnit), MatchResult(Matches[0], &Context)};
  46. }
  47. // Applies \p Selector to \p Match and, on success, returns the selected source.
  48. Expected<StringRef> select(RangeSelector Selector, const TestMatch &Match) {
  49. Expected<CharSourceRange> Range = Selector(Match.Result);
  50. if (!Range)
  51. return Range.takeError();
  52. return tooling::getText(*Range, *Match.Result.Context);
  53. }
  54. // Applies \p Selector to a trivial match with only a single bound node with id
  55. // "bound_node_id". For use in testing unbound-node errors.
  56. Expected<CharSourceRange> selectFromTrivial(const RangeSelector &Selector) {
  57. // We need to bind the result to something, or the match will fail. Use a
  58. // binding that is not used in the unbound node tests.
  59. TestMatch Match =
  60. matchCode("static int x = 0;", varDecl().bind("bound_node_id"));
  61. return Selector(Match.Result);
  62. }
  63. // Matches the message expected for unbound-node failures.
  64. testing::Matcher<StringError> withUnboundNodeMessage() {
  65. return testing::Property(
  66. &StringError::getMessage,
  67. AllOf(HasSubstr("unbound_id"), HasSubstr("not bound")));
  68. }
  69. // Applies \p Selector to code containing assorted node types, where the match
  70. // binds each one: a statement ("stmt"), a (non-member) ctor-initializer
  71. // ("init"), an expression ("expr") and a (nameless) declaration ("decl"). Used
  72. // to test failures caused by applying selectors to nodes of the wrong type.
  73. Expected<CharSourceRange> selectFromAssorted(RangeSelector Selector) {
  74. StringRef Code = R"cc(
  75. struct A {};
  76. class F : public A {
  77. public:
  78. F(int) {}
  79. };
  80. void g() { F f(1); }
  81. )cc";
  82. auto Matcher =
  83. compoundStmt(
  84. hasDescendant(
  85. cxxConstructExpr(
  86. hasDeclaration(
  87. decl(hasDescendant(cxxCtorInitializer(isBaseInitializer())
  88. .bind("init")))
  89. .bind("decl")))
  90. .bind("expr")))
  91. .bind("stmt");
  92. return Selector(matchCode(Code, Matcher).Result);
  93. }
  94. // Matches the message expected for type-error failures.
  95. testing::Matcher<StringError> withTypeErrorMessage(StringRef NodeID) {
  96. return testing::Property(
  97. &StringError::getMessage,
  98. AllOf(HasSubstr(NodeID), HasSubstr("mismatched type")));
  99. }
  100. TEST(RangeSelectorTest, UnboundNode) {
  101. EXPECT_THAT_EXPECTED(selectFromTrivial(node("unbound_id")),
  102. Failed<StringError>(withUnboundNodeMessage()));
  103. }
  104. MATCHER_P(EqualsCharSourceRange, Range, "") {
  105. return Range.getAsRange() == arg.getAsRange() &&
  106. Range.isTokenRange() == arg.isTokenRange();
  107. }
  108. // FIXME: here and elsewhere: use llvm::Annotations library to explicitly mark
  109. // points and ranges of interest, enabling more readable tests.
  110. TEST(RangeSelectorTest, BeforeOp) {
  111. StringRef Code = R"cc(
  112. int f(int x, int y, int z) { return 3; }
  113. int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
  114. )cc";
  115. StringRef Call = "call";
  116. TestMatch Match = matchCode(Code, callExpr().bind(Call));
  117. const auto* E = Match.Result.Nodes.getNodeAs<Expr>(Call);
  118. assert(E != nullptr);
  119. auto ExprBegin = E->getSourceRange().getBegin();
  120. EXPECT_THAT_EXPECTED(
  121. before(node(Call))(Match.Result),
  122. HasValue(EqualsCharSourceRange(
  123. CharSourceRange::getCharRange(ExprBegin, ExprBegin))));
  124. }
  125. TEST(RangeSelectorTest, AfterOp) {
  126. StringRef Code = R"cc(
  127. int f(int x, int y, int z) { return 3; }
  128. int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
  129. )cc";
  130. StringRef Call = "call";
  131. TestMatch Match = matchCode(Code, callExpr().bind(Call));
  132. const auto* E = Match.Result.Nodes.getNodeAs<Expr>(Call);
  133. assert(E != nullptr);
  134. const SourceRange Range = E->getSourceRange();
  135. // The end token, a right paren, is one character wide, so advance by one,
  136. // bringing us to the semicolon.
  137. const SourceLocation SemiLoc = Range.getEnd().getLocWithOffset(1);
  138. const auto ExpectedAfter = CharSourceRange::getCharRange(SemiLoc, SemiLoc);
  139. // Test with a char range.
  140. auto CharRange = CharSourceRange::getCharRange(Range.getBegin(), SemiLoc);
  141. EXPECT_THAT_EXPECTED(after(charRange(CharRange))(Match.Result),
  142. HasValue(EqualsCharSourceRange(ExpectedAfter)));
  143. // Test with a token range.
  144. auto TokenRange = CharSourceRange::getTokenRange(Range);
  145. EXPECT_THAT_EXPECTED(after(charRange(TokenRange))(Match.Result),
  146. HasValue(EqualsCharSourceRange(ExpectedAfter)));
  147. }
  148. TEST(RangeSelectorTest, RangeOp) {
  149. StringRef Code = R"cc(
  150. int f(int x, int y, int z) { return 3; }
  151. int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
  152. )cc";
  153. StringRef Arg0 = "a0";
  154. StringRef Arg1 = "a1";
  155. StringRef Call = "call";
  156. auto Matcher = callExpr(hasArgument(0, expr().bind(Arg0)),
  157. hasArgument(1, expr().bind(Arg1)))
  158. .bind(Call);
  159. TestMatch Match = matchCode(Code, Matcher);
  160. // Node-id specific version:
  161. EXPECT_THAT_EXPECTED(select(range(Arg0, Arg1), Match), HasValue("3, 7"));
  162. // General version:
  163. EXPECT_THAT_EXPECTED(select(range(node(Arg0), node(Arg1)), Match),
  164. HasValue("3, 7"));
  165. }
  166. TEST(RangeSelectorTest, NodeOpStatement) {
  167. StringRef Code = "int f() { return 3; }";
  168. StringRef ID = "id";
  169. TestMatch Match = matchCode(Code, returnStmt().bind(ID));
  170. EXPECT_THAT_EXPECTED(select(node(ID), Match), HasValue("return 3;"));
  171. }
  172. TEST(RangeSelectorTest, NodeOpExpression) {
  173. StringRef Code = "int f() { return 3; }";
  174. StringRef ID = "id";
  175. TestMatch Match = matchCode(Code, expr().bind(ID));
  176. EXPECT_THAT_EXPECTED(select(node(ID), Match), HasValue("3"));
  177. }
  178. TEST(RangeSelectorTest, StatementOp) {
  179. StringRef Code = "int f() { return 3; }";
  180. StringRef ID = "id";
  181. TestMatch Match = matchCode(Code, expr().bind(ID));
  182. EXPECT_THAT_EXPECTED(select(statement(ID), Match), HasValue("3;"));
  183. }
  184. TEST(RangeSelectorTest, MemberOp) {
  185. StringRef Code = R"cc(
  186. struct S {
  187. int member;
  188. };
  189. int g() {
  190. S s;
  191. return s.member;
  192. }
  193. )cc";
  194. StringRef ID = "id";
  195. TestMatch Match = matchCode(Code, memberExpr().bind(ID));
  196. EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
  197. }
  198. // Tests that member does not select any qualifiers on the member name.
  199. TEST(RangeSelectorTest, MemberOpQualified) {
  200. StringRef Code = R"cc(
  201. struct S {
  202. int member;
  203. };
  204. struct T : public S {
  205. int field;
  206. };
  207. int g() {
  208. T t;
  209. return t.S::member;
  210. }
  211. )cc";
  212. StringRef ID = "id";
  213. TestMatch Match = matchCode(Code, memberExpr().bind(ID));
  214. EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
  215. }
  216. TEST(RangeSelectorTest, MemberOpTemplate) {
  217. StringRef Code = R"cc(
  218. struct S {
  219. template <typename T> T foo(T t);
  220. };
  221. int f(int x) {
  222. S s;
  223. return s.template foo<int>(3);
  224. }
  225. )cc";
  226. StringRef ID = "id";
  227. TestMatch Match = matchCode(Code, memberExpr().bind(ID));
  228. EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("foo"));
  229. }
  230. TEST(RangeSelectorTest, MemberOpOperator) {
  231. StringRef Code = R"cc(
  232. struct S {
  233. int operator*();
  234. };
  235. int f(int x) {
  236. S s;
  237. return s.operator *();
  238. }
  239. )cc";
  240. StringRef ID = "id";
  241. TestMatch Match = matchCode(Code, memberExpr().bind(ID));
  242. EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("operator *"));
  243. }
  244. TEST(RangeSelectorTest, NameOpNamedDecl) {
  245. StringRef Code = R"cc(
  246. int myfun() {
  247. return 3;
  248. }
  249. )cc";
  250. StringRef ID = "id";
  251. TestMatch Match = matchCode(Code, functionDecl().bind(ID));
  252. EXPECT_THAT_EXPECTED(select(name(ID), Match), HasValue("myfun"));
  253. }
  254. TEST(RangeSelectorTest, NameOpDeclRef) {
  255. StringRef Code = R"cc(
  256. int foo(int x) {
  257. return x;
  258. }
  259. int g(int x) { return foo(x) * x; }
  260. )cc";
  261. StringRef Ref = "ref";
  262. TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));
  263. EXPECT_THAT_EXPECTED(select(name(Ref), Match), HasValue("foo"));
  264. }
  265. TEST(RangeSelectorTest, NameOpCtorInitializer) {
  266. StringRef Code = R"cc(
  267. class C {
  268. public:
  269. C() : field(3) {}
  270. int field;
  271. };
  272. )cc";
  273. StringRef Init = "init";
  274. TestMatch Match = matchCode(Code, cxxCtorInitializer().bind(Init));
  275. EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field"));
  276. }
  277. TEST(RangeSelectorTest, NameOpErrors) {
  278. EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")),
  279. Failed<StringError>(withUnboundNodeMessage()));
  280. EXPECT_THAT_EXPECTED(selectFromAssorted(name("stmt")),
  281. Failed<StringError>(withTypeErrorMessage("stmt")));
  282. }
  283. TEST(RangeSelectorTest, NameOpDeclRefError) {
  284. StringRef Code = R"cc(
  285. struct S {
  286. int operator*();
  287. };
  288. int f(int x) {
  289. S s;
  290. return *s + x;
  291. }
  292. )cc";
  293. StringRef Ref = "ref";
  294. TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));
  295. EXPECT_THAT_EXPECTED(
  296. name(Ref)(Match.Result),
  297. Failed<StringError>(testing::Property(
  298. &StringError::getMessage,
  299. AllOf(HasSubstr(Ref), HasSubstr("requires property 'identifier'")))));
  300. }
  301. TEST(RangeSelectorTest, CallArgsOp) {
  302. const StringRef Code = R"cc(
  303. struct C {
  304. int bar(int, int);
  305. };
  306. int f() {
  307. C x;
  308. return x.bar(3, 4);
  309. }
  310. )cc";
  311. StringRef ID = "id";
  312. TestMatch Match = matchCode(Code, callExpr().bind(ID));
  313. EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
  314. }
  315. TEST(RangeSelectorTest, CallArgsOpNoArgs) {
  316. const StringRef Code = R"cc(
  317. struct C {
  318. int bar();
  319. };
  320. int f() {
  321. C x;
  322. return x.bar();
  323. }
  324. )cc";
  325. StringRef ID = "id";
  326. TestMatch Match = matchCode(Code, callExpr().bind(ID));
  327. EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(""));
  328. }
  329. TEST(RangeSelectorTest, CallArgsOpNoArgsWithComments) {
  330. const StringRef Code = R"cc(
  331. struct C {
  332. int bar();
  333. };
  334. int f() {
  335. C x;
  336. return x.bar(/*empty*/);
  337. }
  338. )cc";
  339. StringRef ID = "id";
  340. TestMatch Match = matchCode(Code, callExpr().bind(ID));
  341. EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("/*empty*/"));
  342. }
  343. // Tests that arguments are extracted correctly when a temporary (with parens)
  344. // is used.
  345. TEST(RangeSelectorTest, CallArgsOpWithParens) {
  346. const StringRef Code = R"cc(
  347. struct C {
  348. int bar(int, int) { return 3; }
  349. };
  350. int f() {
  351. C x;
  352. return C().bar(3, 4);
  353. }
  354. )cc";
  355. StringRef ID = "id";
  356. TestMatch Match =
  357. matchCode(Code, callExpr(callee(functionDecl(hasName("bar")))).bind(ID));
  358. EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
  359. }
  360. TEST(RangeSelectorTest, CallArgsOpLeadingComments) {
  361. const StringRef Code = R"cc(
  362. struct C {
  363. int bar(int, int) { return 3; }
  364. };
  365. int f() {
  366. C x;
  367. return x.bar(/*leading*/ 3, 4);
  368. }
  369. )cc";
  370. StringRef ID = "id";
  371. TestMatch Match = matchCode(Code, callExpr().bind(ID));
  372. EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
  373. HasValue("/*leading*/ 3, 4"));
  374. }
  375. TEST(RangeSelectorTest, CallArgsOpTrailingComments) {
  376. const StringRef Code = R"cc(
  377. struct C {
  378. int bar(int, int) { return 3; }
  379. };
  380. int f() {
  381. C x;
  382. return x.bar(3 /*trailing*/, 4);
  383. }
  384. )cc";
  385. StringRef ID = "id";
  386. TestMatch Match = matchCode(Code, callExpr().bind(ID));
  387. EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
  388. HasValue("3 /*trailing*/, 4"));
  389. }
  390. TEST(RangeSelectorTest, CallArgsOpEolComments) {
  391. const StringRef Code = R"cc(
  392. struct C {
  393. int bar(int, int) { return 3; }
  394. };
  395. int f() {
  396. C x;
  397. return x.bar( // Header
  398. 1, // foo
  399. 2 // bar
  400. );
  401. }
  402. )cc";
  403. StringRef ID = "id";
  404. TestMatch Match = matchCode(Code, callExpr().bind(ID));
  405. std::string ExpectedString = R"( // Header
  406. 1, // foo
  407. 2 // bar
  408. )";
  409. EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(ExpectedString));
  410. }
  411. TEST(RangeSelectorTest, CallArgsErrors) {
  412. EXPECT_THAT_EXPECTED(selectFromTrivial(callArgs("unbound_id")),
  413. Failed<StringError>(withUnboundNodeMessage()));
  414. EXPECT_THAT_EXPECTED(selectFromAssorted(callArgs("stmt")),
  415. Failed<StringError>(withTypeErrorMessage("stmt")));
  416. }
  417. TEST(RangeSelectorTest, StatementsOp) {
  418. StringRef Code = R"cc(
  419. void g();
  420. void f() { /* comment */ g(); /* comment */ g(); /* comment */ }
  421. )cc";
  422. StringRef ID = "id";
  423. TestMatch Match = matchCode(Code, compoundStmt().bind(ID));
  424. EXPECT_THAT_EXPECTED(
  425. select(statements(ID), Match),
  426. HasValue(" /* comment */ g(); /* comment */ g(); /* comment */ "));
  427. }
  428. TEST(RangeSelectorTest, StatementsOpEmptyList) {
  429. StringRef Code = "void f() {}";
  430. StringRef ID = "id";
  431. TestMatch Match = matchCode(Code, compoundStmt().bind(ID));
  432. EXPECT_THAT_EXPECTED(select(statements(ID), Match), HasValue(""));
  433. }
  434. TEST(RangeSelectorTest, StatementsOpErrors) {
  435. EXPECT_THAT_EXPECTED(selectFromTrivial(statements("unbound_id")),
  436. Failed<StringError>(withUnboundNodeMessage()));
  437. EXPECT_THAT_EXPECTED(selectFromAssorted(statements("decl")),
  438. Failed<StringError>(withTypeErrorMessage("decl")));
  439. }
  440. TEST(RangeSelectorTest, ElementsOp) {
  441. StringRef Code = R"cc(
  442. void f() {
  443. int v[] = {/* comment */ 3, /* comment*/ 4 /* comment */};
  444. (void)v;
  445. }
  446. )cc";
  447. StringRef ID = "id";
  448. TestMatch Match = matchCode(Code, initListExpr().bind(ID));
  449. EXPECT_THAT_EXPECTED(
  450. select(initListElements(ID), Match),
  451. HasValue("/* comment */ 3, /* comment*/ 4 /* comment */"));
  452. }
  453. TEST(RangeSelectorTest, ElementsOpEmptyList) {
  454. StringRef Code = R"cc(
  455. void f() {
  456. int v[] = {};
  457. (void)v;
  458. }
  459. )cc";
  460. StringRef ID = "id";
  461. TestMatch Match = matchCode(Code, initListExpr().bind(ID));
  462. EXPECT_THAT_EXPECTED(select(initListElements(ID), Match), HasValue(""));
  463. }
  464. TEST(RangeSelectorTest, ElementsOpErrors) {
  465. EXPECT_THAT_EXPECTED(selectFromTrivial(initListElements("unbound_id")),
  466. Failed<StringError>(withUnboundNodeMessage()));
  467. EXPECT_THAT_EXPECTED(selectFromAssorted(initListElements("stmt")),
  468. Failed<StringError>(withTypeErrorMessage("stmt")));
  469. }
  470. TEST(RangeSelectorTest, ElseBranchOpSingleStatement) {
  471. StringRef Code = R"cc(
  472. int f() {
  473. int x = 0;
  474. if (true) x = 3;
  475. else x = 4;
  476. return x + 5;
  477. }
  478. )cc";
  479. StringRef ID = "id";
  480. TestMatch Match = matchCode(Code, ifStmt().bind(ID));
  481. EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), HasValue("else x = 4;"));
  482. }
  483. TEST(RangeSelectorTest, ElseBranchOpCompoundStatement) {
  484. StringRef Code = R"cc(
  485. int f() {
  486. int x = 0;
  487. if (true) x = 3;
  488. else { x = 4; }
  489. return x + 5;
  490. }
  491. )cc";
  492. StringRef ID = "id";
  493. TestMatch Match = matchCode(Code, ifStmt().bind(ID));
  494. EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match),
  495. HasValue("else { x = 4; }"));
  496. }
  497. // Tests case where the matched node is the complete expanded text.
  498. TEST(RangeSelectorTest, ExpansionOp) {
  499. StringRef Code = R"cc(
  500. #define BADDECL(E) int bad(int x) { return E; }
  501. BADDECL(x * x)
  502. )cc";
  503. StringRef Fun = "Fun";
  504. TestMatch Match = matchCode(Code, functionDecl(hasName("bad")).bind(Fun));
  505. EXPECT_THAT_EXPECTED(select(expansion(node(Fun)), Match),
  506. HasValue("BADDECL(x * x)"));
  507. }
  508. // Tests case where the matched node is (only) part of the expanded text.
  509. TEST(RangeSelectorTest, ExpansionOpPartial) {
  510. StringRef Code = R"cc(
  511. #define BADDECL(E) int bad(int x) { return E; }
  512. BADDECL(x * x)
  513. )cc";
  514. StringRef Ret = "Ret";
  515. TestMatch Match = matchCode(Code, returnStmt().bind(Ret));
  516. EXPECT_THAT_EXPECTED(select(expansion(node(Ret)), Match),
  517. HasValue("BADDECL(x * x)"));
  518. }
  519. TEST(RangeSelectorTest, IfBoundOpBound) {
  520. StringRef Code = R"cc(
  521. int f() {
  522. return 3 + 5;
  523. }
  524. )cc";
  525. StringRef ID = "id", Op = "op";
  526. TestMatch Match =
  527. matchCode(Code, binaryOperator(hasLHS(expr().bind(ID))).bind(Op));
  528. EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),
  529. HasValue("3"));
  530. }
  531. TEST(RangeSelectorTest, IfBoundOpUnbound) {
  532. StringRef Code = R"cc(
  533. int f() {
  534. return 3 + 5;
  535. }
  536. )cc";
  537. StringRef ID = "id", Op = "op";
  538. TestMatch Match = matchCode(Code, binaryOperator().bind(Op));
  539. EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),
  540. HasValue("3 + 5"));
  541. }
  542. } // namespace