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