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