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 // Gets the spelling location `Length` characters after the start of AST node
197 // `Id`.
198 static SourceLocation getSpellingLocAfter(const MatchResult &Result,
199                                           StringRef Id, int Length) {
200   const auto *E = Result.Nodes.getNodeAs<Expr>(Id);
201   assert(E != nullptr);
202   return Result.SourceManager->getSpellingLoc(E->getBeginLoc())
203       .getLocWithOffset(Length);
204 }
205 
206 // Test with a range that is the entire macro arg, but does not end the
207 // expansion itself.
208 TEST(RangeSelectorTest, AfterOpInMacroArg) {
209   StringRef Code = R"cc(
210 #define ISNULL(x) x == nullptr
211     bool g() { int* y; return ISNULL(y); }
212   )cc";
213 
214   TestMatch Match =
215       matchCode(Code, declRefExpr(to(namedDecl(hasName("y")))).bind("yvar"));
216   int YVarLen = 1;
217   SourceLocation After = getSpellingLocAfter(Match.Result, "yvar", YVarLen);
218   CharSourceRange Expected = CharSourceRange::getCharRange(After, After);
219   EXPECT_THAT_EXPECTED(after(node("yvar"))(Match.Result),
220                        HasValue(EqualsCharSourceRange(Expected)));
221 }
222 
223 // Test with a range that is the entire macro arg and ends the expansion itself.
224 TEST(RangeSelectorTest, AfterOpInMacroArgEndsExpansion) {
225   StringRef Code = R"cc(
226 #define ISNULL(x) nullptr == x
227     bool g() { int* y; return ISNULL(y); }
228   )cc";
229 
230   TestMatch Match =
231       matchCode(Code, declRefExpr(to(namedDecl(hasName("y")))).bind("yvar"));
232   int YVarLen = 1;
233   SourceLocation After = getSpellingLocAfter(Match.Result, "yvar", YVarLen);
234   CharSourceRange Expected = CharSourceRange::getCharRange(After, After);
235   EXPECT_THAT_EXPECTED(after(node("yvar"))(Match.Result),
236                        HasValue(EqualsCharSourceRange(Expected)));
237 }
238 
239 TEST(RangeSelectorTest, AfterOpInPartOfMacroArg) {
240   StringRef Code = R"cc(
241 #define ISNULL(x) x == nullptr
242     int* f(int*);
243     bool g() { int* y; return ISNULL(f(y)); }
244   )cc";
245 
246   TestMatch Match =
247       matchCode(Code, declRefExpr(to(namedDecl(hasName("y")))).bind("yvar"));
248   int YVarLen = 1;
249   SourceLocation After = getSpellingLocAfter(Match.Result, "yvar", YVarLen);
250   CharSourceRange Expected = CharSourceRange::getCharRange(After, After);
251   EXPECT_THAT_EXPECTED(after(node("yvar"))(Match.Result),
252                        HasValue(EqualsCharSourceRange(Expected)));
253 }
254 
255 TEST(RangeSelectorTest, BetweenOp) {
256   StringRef Code = R"cc(
257     int f(int x, int y, int z) { return 3; }
258     int g() { return f(3, /* comment */ 7 /* comment */, 9); }
259   )cc";
260   auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),
261                           hasArgument(1, expr().bind("a1")));
262   RangeSelector R = between(node("a0"), node("a1"));
263   TestMatch Match = matchCode(Code, Matcher);
264   EXPECT_THAT_EXPECTED(select(R, Match), HasValue(", /* comment */ "));
265 }
266 
267 TEST(RangeSelectorTest, BetweenOpParsed) {
268   StringRef Code = R"cc(
269     int f(int x, int y, int z) { return 3; }
270     int g() { return f(3, /* comment */ 7 /* comment */, 9); }
271   )cc";
272   auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),
273                           hasArgument(1, expr().bind("a1")));
274   auto R = parseRangeSelector(R"rs(between(node("a0"), node("a1")))rs");
275   ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
276   TestMatch Match = matchCode(Code, Matcher);
277   EXPECT_THAT_EXPECTED(select(*R, Match), HasValue(", /* comment */ "));
278 }
279 
280 // Node-id specific version.
281 TEST(RangeSelectorTest, EncloseOpNodes) {
282   StringRef Code = R"cc(
283     int f(int x, int y, int z) { return 3; }
284     int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
285   )cc";
286   auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),
287                           hasArgument(1, expr().bind("a1")));
288   RangeSelector R = encloseNodes("a0", "a1");
289   TestMatch Match = matchCode(Code, Matcher);
290   EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, 7"));
291 }
292 
293 TEST(RangeSelectorTest, EncloseOpGeneral) {
294   StringRef Code = R"cc(
295     int f(int x, int y, int z) { return 3; }
296     int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
297   )cc";
298   auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),
299                           hasArgument(1, expr().bind("a1")));
300   RangeSelector R = enclose(node("a0"), node("a1"));
301   TestMatch Match = matchCode(Code, Matcher);
302   EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, 7"));
303 }
304 
305 TEST(RangeSelectorTest, EncloseOpNodesParsed) {
306   StringRef Code = R"cc(
307     int f(int x, int y, int z) { return 3; }
308     int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
309   )cc";
310   auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),
311                           hasArgument(1, expr().bind("a1")));
312   auto R = parseRangeSelector(R"rs(encloseNodes("a0", "a1"))rs");
313   ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
314   TestMatch Match = matchCode(Code, Matcher);
315   EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3, 7"));
316 }
317 
318 TEST(RangeSelectorTest, EncloseOpGeneralParsed) {
319   StringRef Code = R"cc(
320     int f(int x, int y, int z) { return 3; }
321     int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
322   )cc";
323   auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),
324                           hasArgument(1, expr().bind("a1")));
325   auto R = parseRangeSelector(R"rs(encloseNodes("a0", "a1"))rs");
326   ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
327   TestMatch Match = matchCode(Code, Matcher);
328   EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3, 7"));
329 }
330 
331 TEST(RangeSelectorTest, NodeOpStatement) {
332   StringRef Code = "int f() { return 3; }";
333   TestMatch Match = matchCode(Code, returnStmt().bind("id"));
334   EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("return 3;"));
335 }
336 
337 TEST(RangeSelectorTest, NodeOpExpression) {
338   StringRef Code = "int f() { return 3; }";
339   TestMatch Match = matchCode(Code, expr().bind("id"));
340   EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("3"));
341 }
342 
343 TEST(RangeSelectorTest, StatementOp) {
344   StringRef Code = "int f() { return 3; }";
345   TestMatch Match = matchCode(Code, expr().bind("id"));
346   RangeSelector R = statement("id");
347   EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3;"));
348 }
349 
350 TEST(RangeSelectorTest, StatementOpParsed) {
351   StringRef Code = "int f() { return 3; }";
352   TestMatch Match = matchCode(Code, expr().bind("id"));
353   auto R = parseRangeSelector(R"rs(statement("id"))rs");
354   ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
355   EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3;"));
356 }
357 
358 TEST(RangeSelectorTest, MemberOp) {
359   StringRef Code = R"cc(
360     struct S {
361       int member;
362     };
363     int g() {
364       S s;
365       return s.member;
366     }
367   )cc";
368   const char *ID = "id";
369   TestMatch Match = matchCode(Code, memberExpr().bind(ID));
370   EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
371 }
372 
373 // Tests that member does not select any qualifiers on the member name.
374 TEST(RangeSelectorTest, MemberOpQualified) {
375   StringRef Code = R"cc(
376     struct S {
377       int member;
378     };
379     struct T : public S {
380       int field;
381     };
382     int g() {
383       T t;
384       return t.S::member;
385     }
386   )cc";
387   const char *ID = "id";
388   TestMatch Match = matchCode(Code, memberExpr().bind(ID));
389   EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
390 }
391 
392 TEST(RangeSelectorTest, MemberOpTemplate) {
393   StringRef Code = R"cc(
394     struct S {
395       template <typename T> T foo(T t);
396     };
397     int f(int x) {
398       S s;
399       return s.template foo<int>(3);
400     }
401   )cc";
402 
403   const char *ID = "id";
404   TestMatch Match = matchCode(Code, memberExpr().bind(ID));
405   EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("foo"));
406 }
407 
408 TEST(RangeSelectorTest, MemberOpOperator) {
409   StringRef Code = R"cc(
410     struct S {
411       int operator*();
412     };
413     int f(int x) {
414       S s;
415       return s.operator *();
416     }
417   )cc";
418 
419   const char *ID = "id";
420   TestMatch Match = matchCode(Code, memberExpr().bind(ID));
421   EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("operator *"));
422 }
423 
424 TEST(RangeSelectorTest, NameOpNamedDecl) {
425   StringRef Code = R"cc(
426     int myfun() {
427       return 3;
428     }
429   )cc";
430   const char *ID = "id";
431   TestMatch Match = matchCode(Code, functionDecl().bind(ID));
432   EXPECT_THAT_EXPECTED(select(name(ID), Match), HasValue("myfun"));
433 }
434 
435 TEST(RangeSelectorTest, NameOpDeclRef) {
436   StringRef Code = R"cc(
437     int foo(int x) {
438       return x;
439     }
440     int g(int x) { return foo(x) * x; }
441   )cc";
442   const char *Ref = "ref";
443   TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));
444   EXPECT_THAT_EXPECTED(select(name(Ref), Match), HasValue("foo"));
445 }
446 
447 TEST(RangeSelectorTest, NameOpCtorInitializer) {
448   StringRef Code = R"cc(
449     class C {
450      public:
451       C() : field(3) {}
452       int field;
453     };
454   )cc";
455   const char *Init = "init";
456   TestMatch Match = matchCode(Code, cxxCtorInitializer().bind(Init));
457   EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field"));
458 }
459 
460 TEST(RangeSelectorTest, NameOpErrors) {
461   EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")),
462                        Failed<StringError>(withUnboundNodeMessage()));
463   EXPECT_THAT_EXPECTED(selectFromAssorted(name("stmt")),
464                        Failed<StringError>(withTypeErrorMessage("stmt")));
465 }
466 
467 TEST(RangeSelectorTest, NameOpDeclRefError) {
468   StringRef Code = R"cc(
469     struct S {
470       int operator*();
471     };
472     int f(int x) {
473       S s;
474       return *s + x;
475     }
476   )cc";
477   const char *Ref = "ref";
478   TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));
479   EXPECT_THAT_EXPECTED(
480       name(Ref)(Match.Result),
481       Failed<StringError>(testing::Property(
482           &StringError::getMessage,
483           AllOf(HasSubstr(Ref), HasSubstr("requires property 'identifier'")))));
484 }
485 
486 TEST(RangeSelectorTest, CallArgsOp) {
487   const StringRef Code = R"cc(
488     struct C {
489       int bar(int, int);
490     };
491     int f() {
492       C x;
493       return x.bar(3, 4);
494     }
495   )cc";
496   const char *ID = "id";
497   TestMatch Match = matchCode(Code, callExpr().bind(ID));
498   EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
499 }
500 
501 TEST(RangeSelectorTest, CallArgsOpNoArgs) {
502   const StringRef Code = R"cc(
503     struct C {
504       int bar();
505     };
506     int f() {
507       C x;
508       return x.bar();
509     }
510   )cc";
511   const char *ID = "id";
512   TestMatch Match = matchCode(Code, callExpr().bind(ID));
513   EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(""));
514 }
515 
516 TEST(RangeSelectorTest, CallArgsOpNoArgsWithComments) {
517   const StringRef Code = R"cc(
518     struct C {
519       int bar();
520     };
521     int f() {
522       C x;
523       return x.bar(/*empty*/);
524     }
525   )cc";
526   const char *ID = "id";
527   TestMatch Match = matchCode(Code, callExpr().bind(ID));
528   EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("/*empty*/"));
529 }
530 
531 // Tests that arguments are extracted correctly when a temporary (with parens)
532 // is used.
533 TEST(RangeSelectorTest, CallArgsOpWithParens) {
534   const StringRef Code = R"cc(
535     struct C {
536       int bar(int, int) { return 3; }
537     };
538     int f() {
539       C x;
540       return C().bar(3, 4);
541     }
542   )cc";
543   const char *ID = "id";
544   TestMatch Match =
545       matchCode(Code, callExpr(callee(functionDecl(hasName("bar")))).bind(ID));
546   EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
547 }
548 
549 TEST(RangeSelectorTest, CallArgsOpLeadingComments) {
550   const StringRef Code = R"cc(
551     struct C {
552       int bar(int, int) { return 3; }
553     };
554     int f() {
555       C x;
556       return x.bar(/*leading*/ 3, 4);
557     }
558   )cc";
559   const char *ID = "id";
560   TestMatch Match = matchCode(Code, callExpr().bind(ID));
561   EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
562                        HasValue("/*leading*/ 3, 4"));
563 }
564 
565 TEST(RangeSelectorTest, CallArgsOpTrailingComments) {
566   const StringRef Code = R"cc(
567     struct C {
568       int bar(int, int) { return 3; }
569     };
570     int f() {
571       C x;
572       return x.bar(3 /*trailing*/, 4);
573     }
574   )cc";
575   const char *ID = "id";
576   TestMatch Match = matchCode(Code, callExpr().bind(ID));
577   EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
578                        HasValue("3 /*trailing*/, 4"));
579 }
580 
581 TEST(RangeSelectorTest, CallArgsOpEolComments) {
582   const StringRef Code = R"cc(
583     struct C {
584       int bar(int, int) { return 3; }
585     };
586     int f() {
587       C x;
588       return x.bar(  // Header
589           1,           // foo
590           2            // bar
591       );
592     }
593   )cc";
594   const char *ID = "id";
595   TestMatch Match = matchCode(Code, callExpr().bind(ID));
596   std::string ExpectedString = R"(  // Header
597           1,           // foo
598           2            // bar
599       )";
600   EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(ExpectedString));
601 }
602 
603 TEST(RangeSelectorTest, CallArgsErrors) {
604   EXPECT_THAT_EXPECTED(selectFromTrivial(callArgs("unbound_id")),
605                        Failed<StringError>(withUnboundNodeMessage()));
606   EXPECT_THAT_EXPECTED(selectFromAssorted(callArgs("stmt")),
607                        Failed<StringError>(withTypeErrorMessage("stmt")));
608 }
609 
610 TEST(RangeSelectorTest, StatementsOp) {
611   StringRef Code = R"cc(
612     void g();
613     void f() { /* comment */ g(); /* comment */ g(); /* comment */ }
614   )cc";
615   const char *ID = "id";
616   TestMatch Match = matchCode(Code, compoundStmt().bind(ID));
617   EXPECT_THAT_EXPECTED(
618       select(statements(ID), Match),
619       HasValue(" /* comment */ g(); /* comment */ g(); /* comment */ "));
620 }
621 
622 TEST(RangeSelectorTest, StatementsOpEmptyList) {
623   StringRef Code = "void f() {}";
624   const char *ID = "id";
625   TestMatch Match = matchCode(Code, compoundStmt().bind(ID));
626   EXPECT_THAT_EXPECTED(select(statements(ID), Match), HasValue(""));
627 }
628 
629 TEST(RangeSelectorTest, StatementsOpErrors) {
630   EXPECT_THAT_EXPECTED(selectFromTrivial(statements("unbound_id")),
631                        Failed<StringError>(withUnboundNodeMessage()));
632   EXPECT_THAT_EXPECTED(selectFromAssorted(statements("decl")),
633                        Failed<StringError>(withTypeErrorMessage("decl")));
634 }
635 
636 TEST(RangeSelectorTest, ElementsOp) {
637   StringRef Code = R"cc(
638     void f() {
639       int v[] = {/* comment */ 3, /* comment*/ 4 /* comment */};
640       (void)v;
641     }
642   )cc";
643   const char *ID = "id";
644   TestMatch Match = matchCode(Code, initListExpr().bind(ID));
645   EXPECT_THAT_EXPECTED(
646       select(initListElements(ID), Match),
647       HasValue("/* comment */ 3, /* comment*/ 4 /* comment */"));
648 }
649 
650 TEST(RangeSelectorTest, ElementsOpEmptyList) {
651   StringRef Code = R"cc(
652     void f() {
653       int v[] = {};
654       (void)v;
655     }
656   )cc";
657   const char *ID = "id";
658   TestMatch Match = matchCode(Code, initListExpr().bind(ID));
659   EXPECT_THAT_EXPECTED(select(initListElements(ID), Match), HasValue(""));
660 }
661 
662 TEST(RangeSelectorTest, ElementsOpErrors) {
663   EXPECT_THAT_EXPECTED(selectFromTrivial(initListElements("unbound_id")),
664                        Failed<StringError>(withUnboundNodeMessage()));
665   EXPECT_THAT_EXPECTED(selectFromAssorted(initListElements("stmt")),
666                        Failed<StringError>(withTypeErrorMessage("stmt")));
667 }
668 
669 TEST(RangeSelectorTest, ElseBranchOpSingleStatement) {
670   StringRef Code = R"cc(
671     int f() {
672       int x = 0;
673       if (true) x = 3;
674       else x = 4;
675       return x + 5;
676     }
677   )cc";
678   const char *ID = "id";
679   TestMatch Match = matchCode(Code, ifStmt().bind(ID));
680   EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), HasValue("else x = 4;"));
681 }
682 
683 TEST(RangeSelectorTest, ElseBranchOpCompoundStatement) {
684   StringRef Code = R"cc(
685     int f() {
686       int x = 0;
687       if (true) x = 3;
688       else { x = 4; }
689       return x + 5;
690     }
691   )cc";
692   const char *ID = "id";
693   TestMatch Match = matchCode(Code, ifStmt().bind(ID));
694   EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match),
695                        HasValue("else { x = 4; }"));
696 }
697 
698 // Tests case where the matched node is the complete expanded text.
699 TEST(RangeSelectorTest, ExpansionOp) {
700   StringRef Code = R"cc(
701 #define BADDECL(E) int bad(int x) { return E; }
702     BADDECL(x * x)
703   )cc";
704 
705   const char *Fun = "Fun";
706   TestMatch Match = matchCode(Code, functionDecl(hasName("bad")).bind(Fun));
707   EXPECT_THAT_EXPECTED(select(expansion(node(Fun)), Match),
708                        HasValue("BADDECL(x * x)"));
709 }
710 
711 // Tests case where the matched node is (only) part of the expanded text.
712 TEST(RangeSelectorTest, ExpansionOpPartial) {
713   StringRef Code = R"cc(
714 #define BADDECL(E) int bad(int x) { return E; }
715     BADDECL(x * x)
716   )cc";
717 
718   const char *Ret = "Ret";
719   TestMatch Match = matchCode(Code, returnStmt().bind(Ret));
720   EXPECT_THAT_EXPECTED(select(expansion(node(Ret)), Match),
721                        HasValue("BADDECL(x * x)"));
722 }
723 
724 TEST(RangeSelectorTest, IfBoundOpBound) {
725   StringRef Code = R"cc(
726     int f() {
727       return 3 + 5;
728     }
729   )cc";
730   const char *ID = "id", *Op = "op";
731   TestMatch Match =
732       matchCode(Code, binaryOperator(hasLHS(expr().bind(ID))).bind(Op));
733   EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),
734                        HasValue("3"));
735 }
736 
737 TEST(RangeSelectorTest, IfBoundOpUnbound) {
738   StringRef Code = R"cc(
739     int f() {
740       return 3 + 5;
741     }
742   )cc";
743   const char *ID = "id", *Op = "op";
744   TestMatch Match = matchCode(Code, binaryOperator().bind(Op));
745   EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),
746                        HasValue("3 + 5"));
747 }
748 
749 } // namespace
750