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
20using namespace clang;
21using namespace transformer;
22using namespace ast_matchers;
23
24namespace {
25using ::llvm::Expected;
26using ::llvm::Failed;
27using ::llvm::HasValue;
28using ::llvm::StringError;
29using ::testing::AllOf;
30using ::testing::HasSubstr;
31
32using MatchResult = MatchFinder::MatchResult;
33
34struct 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
42template <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 TraversalKindScope RAII(Context, TK_AsIs);
50 auto Matches = ast_matchers::match(Matcher, Context);
51 // We expect a single, exact match.
52 assert(Matches.size() != 0 && "no matches found");
53 assert(Matches.size() == 1 && "too many matches");
54
55 return TestMatch{.ASTUnit: std::move(ASTUnit), .Result: MatchResult(Matches[0], &Context)};
56}
57
58// Applies \p Selector to \p Match and, on success, returns the selected source.
59Expected<StringRef> select(RangeSelector Selector, const TestMatch &Match) {
60 Expected<CharSourceRange> Range = Selector(Match.Result);
61 if (!Range)
62 return Range.takeError();
63 return tooling::getText(Range: *Range, Context: *Match.Result.Context);
64}
65
66// Applies \p Selector to a trivial match with only a single bound node with id
67// "bound_node_id". For use in testing unbound-node errors.
68Expected<CharSourceRange> selectFromTrivial(const RangeSelector &Selector) {
69 // We need to bind the result to something, or the match will fail. Use a
70 // binding that is not used in the unbound node tests.
71 TestMatch Match =
72 matchCode(Code: "static int x = 0;", Matcher: varDecl().bind(ID: "bound_node_id"));
73 return Selector(Match.Result);
74}
75
76// Matches the message expected for unbound-node failures.
77testing::Matcher<StringError> withUnboundNodeMessage() {
78 return testing::Property(
79 property: &StringError::getMessage,
80 matcher: AllOf(matchers: HasSubstr(substring: "unbound_id"), matchers: HasSubstr(substring: "not bound")));
81}
82
83// Applies \p Selector to code containing assorted node types, where the match
84// binds each one: a statement ("stmt"), a (non-member) ctor-initializer
85// ("init"), an expression ("expr") and a (nameless) declaration ("decl"). Used
86// to test failures caused by applying selectors to nodes of the wrong type.
87Expected<CharSourceRange> selectFromAssorted(RangeSelector Selector) {
88 StringRef Code = R"cc(
89 struct A {};
90 class F : public A {
91 public:
92 F(int) {}
93 };
94 void g() { F f(1); }
95 )cc";
96
97 auto Matcher =
98 compoundStmt(
99 hasDescendant(
100 cxxConstructExpr(
101 hasDeclaration(
102 InnerMatcher: decl(hasDescendant(cxxCtorInitializer(isBaseInitializer())
103 .bind(ID: "init")))
104 .bind(ID: "decl")))
105 .bind(ID: "expr")))
106 .bind(ID: "stmt");
107
108 return Selector(matchCode(Code, Matcher).Result);
109}
110
111// Matches the message expected for type-error failures.
112testing::Matcher<StringError> withTypeErrorMessage(const std::string &NodeID) {
113 return testing::Property(
114 property: &StringError::getMessage,
115 matcher: AllOf(matchers: HasSubstr(substring: NodeID), matchers: HasSubstr(substring: "mismatched type")));
116}
117
118TEST(RangeSelectorTest, UnboundNode) {
119 EXPECT_THAT_EXPECTED(selectFromTrivial(node("unbound_id")),
120 Failed<StringError>(withUnboundNodeMessage()));
121}
122
123MATCHER_P(EqualsCharSourceRange, Range, "") {
124 return Range.getAsRange() == arg.getAsRange() &&
125 Range.isTokenRange() == arg.isTokenRange();
126}
127
128// FIXME: here and elsewhere: use llvm::Annotations library to explicitly mark
129// points and ranges of interest, enabling more readable tests.
130TEST(RangeSelectorTest, BeforeOp) {
131 StringRef Code = R"cc(
132 int f(int x, int y, int z) { return 3; }
133 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
134 )cc";
135 StringRef CallID = "call";
136 ast_matchers::internal::Matcher<Stmt> M = callExpr().bind(ID: CallID);
137 RangeSelector R = before(Selector: node(ID: CallID.str()));
138
139 TestMatch Match = matchCode(Code, Matcher: M);
140 const auto *E = Match.Result.Nodes.getNodeAs<Expr>(ID: CallID);
141 assert(E != nullptr);
142 auto ExprBegin = E->getSourceRange().getBegin();
143 EXPECT_THAT_EXPECTED(
144 R(Match.Result),
145 HasValue(EqualsCharSourceRange(
146 CharSourceRange::getCharRange(ExprBegin, ExprBegin))));
147}
148
149TEST(RangeSelectorTest, BeforeOpParsed) {
150 StringRef Code = R"cc(
151 int f(int x, int y, int z) { return 3; }
152 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
153 )cc";
154 StringRef CallID = "call";
155 ast_matchers::internal::Matcher<Stmt> M = callExpr().bind(ID: CallID);
156 auto R = parseRangeSelector(Input: R"rs(before(node("call")))rs");
157 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
158
159 TestMatch Match = matchCode(Code, Matcher: M);
160 const auto *E = Match.Result.Nodes.getNodeAs<Expr>(ID: CallID);
161 assert(E != nullptr);
162 auto ExprBegin = E->getSourceRange().getBegin();
163 EXPECT_THAT_EXPECTED(
164 (*R)(Match.Result),
165 HasValue(EqualsCharSourceRange(
166 CharSourceRange::getCharRange(ExprBegin, ExprBegin))));
167}
168
169TEST(RangeSelectorTest, AfterOp) {
170 StringRef Code = R"cc(
171 int f(int x, int y, int z) { return 3; }
172 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
173 )cc";
174 StringRef Call = "call";
175 TestMatch Match = matchCode(Code, Matcher: callExpr().bind(ID: Call));
176 const auto* E = Match.Result.Nodes.getNodeAs<Expr>(ID: Call);
177 assert(E != nullptr);
178 const SourceRange Range = E->getSourceRange();
179 // The end token, a right paren, is one character wide, so advance by one,
180 // bringing us to the semicolon.
181 const SourceLocation SemiLoc = Range.getEnd().getLocWithOffset(Offset: 1);
182 const auto ExpectedAfter = CharSourceRange::getCharRange(B: SemiLoc, E: SemiLoc);
183
184 // Test with a char range.
185 auto CharRange = CharSourceRange::getCharRange(B: Range.getBegin(), E: SemiLoc);
186 EXPECT_THAT_EXPECTED(after(charRange(CharRange))(Match.Result),
187 HasValue(EqualsCharSourceRange(ExpectedAfter)));
188
189 // Test with a token range.
190 auto TokenRange = CharSourceRange::getTokenRange(R: Range);
191 EXPECT_THAT_EXPECTED(after(charRange(TokenRange))(Match.Result),
192 HasValue(EqualsCharSourceRange(ExpectedAfter)));
193}
194
195// Gets the spelling location `Length` characters after the start of AST node
196// `Id`.
197static SourceLocation getSpellingLocAfter(const MatchResult &Result,
198 StringRef Id, int Length) {
199 const auto *E = Result.Nodes.getNodeAs<Expr>(ID: Id);
200 assert(E != nullptr);
201 return Result.SourceManager->getSpellingLoc(Loc: E->getBeginLoc())
202 .getLocWithOffset(Length);
203}
204
205// Test with a range that is the entire macro arg, but does not end the
206// expansion itself.
207TEST(RangeSelectorTest, AfterOpInMacroArg) {
208 StringRef Code = R"cc(
209#define ISNULL(x) x == nullptr
210 bool g() { int* y; return ISNULL(y); }
211 )cc";
212
213 TestMatch Match =
214 matchCode(Code, Matcher: declRefExpr(to(InnerMatcher: namedDecl(hasName(Name: "y")))).bind(ID: "yvar"));
215 int YVarLen = 1;
216 SourceLocation After = getSpellingLocAfter(Result: Match.Result, Id: "yvar", Length: YVarLen);
217 CharSourceRange Expected = CharSourceRange::getCharRange(B: After, E: After);
218 EXPECT_THAT_EXPECTED(after(node("yvar"))(Match.Result),
219 HasValue(EqualsCharSourceRange(Expected)));
220}
221
222// Test with a range that is the entire macro arg and ends the expansion itself.
223TEST(RangeSelectorTest, AfterOpInMacroArgEndsExpansion) {
224 StringRef Code = R"cc(
225#define ISNULL(x) nullptr == x
226 bool g() { int* y; return ISNULL(y); }
227 )cc";
228
229 TestMatch Match =
230 matchCode(Code, Matcher: declRefExpr(to(InnerMatcher: namedDecl(hasName(Name: "y")))).bind(ID: "yvar"));
231 int YVarLen = 1;
232 SourceLocation After = getSpellingLocAfter(Result: Match.Result, Id: "yvar", Length: YVarLen);
233 CharSourceRange Expected = CharSourceRange::getCharRange(B: After, E: After);
234 EXPECT_THAT_EXPECTED(after(node("yvar"))(Match.Result),
235 HasValue(EqualsCharSourceRange(Expected)));
236}
237
238TEST(RangeSelectorTest, AfterOpInPartOfMacroArg) {
239 StringRef Code = R"cc(
240#define ISNULL(x) x == nullptr
241 int* f(int*);
242 bool g() { int* y; return ISNULL(f(y)); }
243 )cc";
244
245 TestMatch Match =
246 matchCode(Code, Matcher: declRefExpr(to(InnerMatcher: namedDecl(hasName(Name: "y")))).bind(ID: "yvar"));
247 int YVarLen = 1;
248 SourceLocation After = getSpellingLocAfter(Result: Match.Result, Id: "yvar", Length: YVarLen);
249 CharSourceRange Expected = CharSourceRange::getCharRange(B: After, E: After);
250 EXPECT_THAT_EXPECTED(after(node("yvar"))(Match.Result),
251 HasValue(EqualsCharSourceRange(Expected)));
252}
253
254TEST(RangeSelectorTest, BetweenOp) {
255 StringRef Code = R"cc(
256 int f(int x, int y, int z) { return 3; }
257 int g() { return f(3, /* comment */ 7 /* comment */, 9); }
258 )cc";
259 auto Matcher = callExpr(hasArgument(N: 0, InnerMatcher: expr().bind(ID: "a0")),
260 hasArgument(N: 1, InnerMatcher: expr().bind(ID: "a1")));
261 RangeSelector R = between(R1: node(ID: "a0"), R2: node(ID: "a1"));
262 TestMatch Match = matchCode(Code, Matcher);
263 EXPECT_THAT_EXPECTED(select(R, Match), HasValue(", /* comment */ "));
264}
265
266TEST(RangeSelectorTest, BetweenOpParsed) {
267 StringRef Code = R"cc(
268 int f(int x, int y, int z) { return 3; }
269 int g() { return f(3, /* comment */ 7 /* comment */, 9); }
270 )cc";
271 auto Matcher = callExpr(hasArgument(N: 0, InnerMatcher: expr().bind(ID: "a0")),
272 hasArgument(N: 1, InnerMatcher: expr().bind(ID: "a1")));
273 auto R = parseRangeSelector(Input: R"rs(between(node("a0"), node("a1")))rs");
274 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
275 TestMatch Match = matchCode(Code, Matcher);
276 EXPECT_THAT_EXPECTED(select(*R, Match), HasValue(", /* comment */ "));
277}
278
279// Node-id specific version.
280TEST(RangeSelectorTest, EncloseOpNodes) {
281 StringRef Code = R"cc(
282 int f(int x, int y, int z) { return 3; }
283 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
284 )cc";
285 auto Matcher = callExpr(hasArgument(N: 0, InnerMatcher: expr().bind(ID: "a0")),
286 hasArgument(N: 1, InnerMatcher: expr().bind(ID: "a1")));
287 RangeSelector R = encloseNodes(BeginID: "a0", EndID: "a1");
288 TestMatch Match = matchCode(Code, Matcher);
289 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, 7"));
290}
291
292TEST(RangeSelectorTest, EncloseOpGeneral) {
293 StringRef Code = R"cc(
294 int f(int x, int y, int z) { return 3; }
295 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
296 )cc";
297 auto Matcher = callExpr(hasArgument(N: 0, InnerMatcher: expr().bind(ID: "a0")),
298 hasArgument(N: 1, InnerMatcher: expr().bind(ID: "a1")));
299 RangeSelector R = enclose(Begin: node(ID: "a0"), End: node(ID: "a1"));
300 TestMatch Match = matchCode(Code, Matcher);
301 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, 7"));
302}
303
304TEST(RangeSelectorTest, EncloseOpNodesParsed) {
305 StringRef Code = R"cc(
306 int f(int x, int y, int z) { return 3; }
307 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
308 )cc";
309 auto Matcher = callExpr(hasArgument(N: 0, InnerMatcher: expr().bind(ID: "a0")),
310 hasArgument(N: 1, InnerMatcher: expr().bind(ID: "a1")));
311 auto R = parseRangeSelector(Input: R"rs(encloseNodes("a0", "a1"))rs");
312 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
313 TestMatch Match = matchCode(Code, Matcher);
314 EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3, 7"));
315}
316
317TEST(RangeSelectorTest, EncloseOpGeneralParsed) {
318 StringRef Code = R"cc(
319 int f(int x, int y, int z) { return 3; }
320 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
321 )cc";
322 auto Matcher = callExpr(hasArgument(N: 0, InnerMatcher: expr().bind(ID: "a0")),
323 hasArgument(N: 1, InnerMatcher: expr().bind(ID: "a1")));
324 auto R = parseRangeSelector(Input: R"rs(encloseNodes("a0", "a1"))rs");
325 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
326 TestMatch Match = matchCode(Code, Matcher);
327 EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3, 7"));
328}
329
330TEST(RangeSelectorTest, NodeOpStatement) {
331 StringRef Code = "int f() { return 3; }";
332 TestMatch Match = matchCode(Code, Matcher: returnStmt().bind(ID: "id"));
333 EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("return 3;"));
334}
335
336TEST(RangeSelectorTest, NodeOpExpression) {
337 StringRef Code = "int f() { return 3; }";
338 TestMatch Match = matchCode(Code, Matcher: expr().bind(ID: "id"));
339 EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("3"));
340}
341
342TEST(RangeSelectorTest, StatementOp) {
343 StringRef Code = "int f() { return 3; }";
344 TestMatch Match = matchCode(Code, Matcher: expr().bind(ID: "id"));
345 RangeSelector R = statement(ID: "id");
346 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3;"));
347}
348
349TEST(RangeSelectorTest, StatementOpParsed) {
350 StringRef Code = "int f() { return 3; }";
351 TestMatch Match = matchCode(Code, Matcher: expr().bind(ID: "id"));
352 auto R = parseRangeSelector(Input: R"rs(statement("id"))rs");
353 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());
354 EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3;"));
355}
356
357TEST(RangeSelectorTest, MemberOp) {
358 StringRef Code = R"cc(
359 struct S {
360 int member;
361 };
362 int g() {
363 S s;
364 return s.member;
365 }
366 )cc";
367 const char *ID = "id";
368 TestMatch Match = matchCode(Code, Matcher: memberExpr().bind(ID));
369 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
370}
371
372// Tests that member does not select any qualifiers on the member name.
373TEST(RangeSelectorTest, MemberOpQualified) {
374 StringRef Code = R"cc(
375 struct S {
376 int member;
377 };
378 struct T : public S {
379 int field;
380 };
381 int g() {
382 T t;
383 return t.S::member;
384 }
385 )cc";
386 const char *ID = "id";
387 TestMatch Match = matchCode(Code, Matcher: memberExpr().bind(ID));
388 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
389}
390
391TEST(RangeSelectorTest, MemberOpTemplate) {
392 StringRef Code = R"cc(
393 struct S {
394 template <typename T> T foo(T t);
395 };
396 int f(int x) {
397 S s;
398 return s.template foo<int>(3);
399 }
400 )cc";
401
402 const char *ID = "id";
403 TestMatch Match = matchCode(Code, Matcher: memberExpr().bind(ID));
404 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("foo"));
405}
406
407TEST(RangeSelectorTest, MemberOpOperator) {
408 StringRef Code = R"cc(
409 struct S {
410 int operator*();
411 };
412 int f(int x) {
413 S s;
414 return s.operator *();
415 }
416 )cc";
417
418 const char *ID = "id";
419 TestMatch Match = matchCode(Code, Matcher: memberExpr().bind(ID));
420 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("operator *"));
421}
422
423TEST(RangeSelectorTest, NameOpNamedDecl) {
424 StringRef Code = R"cc(
425 int myfun() {
426 return 3;
427 }
428 )cc";
429 const char *ID = "id";
430 TestMatch Match = matchCode(Code, Matcher: functionDecl().bind(ID));
431 EXPECT_THAT_EXPECTED(select(name(ID), Match), HasValue("myfun"));
432}
433
434TEST(RangeSelectorTest, NameOpDeclRef) {
435 StringRef Code = R"cc(
436 int foo(int x) {
437 return x;
438 }
439 int g(int x) { return foo(x) * x; }
440 )cc";
441 const char *Ref = "ref";
442 TestMatch Match = matchCode(Code, Matcher: declRefExpr(to(InnerMatcher: functionDecl())).bind(ID: Ref));
443 EXPECT_THAT_EXPECTED(select(name(Ref), Match), HasValue("foo"));
444}
445
446TEST(RangeSelectorTest, NameOpCtorInitializer) {
447 StringRef Code = R"cc(
448 class C {
449 public:
450 C() : field(3) {}
451 int field;
452 };
453 )cc";
454 const char *Init = "init";
455 TestMatch Match = matchCode(Code, Matcher: cxxCtorInitializer().bind(ID: Init));
456 EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field"));
457}
458
459TEST(RangeSelectorTest, NameOpTypeLoc) {
460 StringRef Code = R"cc(
461 namespace ns {
462 struct Foo {
463 Foo();
464 Foo(int);
465 Foo(int, int);
466 };
467 } // namespace ns
468
469 ns::Foo a;
470 auto b = ns::Foo(3);
471 auto c = ns::Foo(1, 2);
472 )cc";
473 const char *CtorTy = "ctor_ty";
474 // Matches declaration of `a`
475 TestMatch MatchA = matchCode(
476 Code, Matcher: varDecl(hasName(Name: "a"), hasTypeLoc(Inner: typeLoc().bind(ID: CtorTy))));
477 EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("Foo"));
478 // Matches call of Foo(int)
479 TestMatch MatchB = matchCode(
480 Code, Matcher: cxxFunctionalCastExpr(hasTypeLoc(Inner: typeLoc().bind(ID: CtorTy))));
481 EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("Foo"));
482 // Matches call of Foo(int, int)
483 TestMatch MatchC = matchCode(
484 Code, Matcher: cxxTemporaryObjectExpr(hasTypeLoc(Inner: typeLoc().bind(ID: CtorTy))));
485 EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchC), HasValue("Foo"));
486}
487
488TEST(RangeSelectorTest, NameOpTemplateSpecializationTypeLoc) {
489 StringRef Code = R"cc(
490 namespace ns {
491 template <typename T>
492 struct Foo {};
493 } // namespace ns
494
495 ns::Foo<int> a;
496 )cc";
497 const char *Loc = "tyloc";
498 // Matches declaration of `a`.
499 TestMatch MatchA =
500 matchCode(Code, Matcher: varDecl(hasName(Name: "a"), hasTypeLoc(Inner: typeLoc().bind(ID: Loc))));
501 EXPECT_THAT_EXPECTED(select(name(Loc), MatchA), HasValue("Foo"));
502}
503
504TEST(RangeSelectorTest, NameOpErrors) {
505 EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")),
506 Failed<StringError>(withUnboundNodeMessage()));
507 EXPECT_THAT_EXPECTED(selectFromAssorted(name("stmt")),
508 Failed<StringError>(withTypeErrorMessage("stmt")));
509}
510
511TEST(RangeSelectorTest, NameOpDeclRefError) {
512 StringRef Code = R"cc(
513 struct S {
514 int operator*();
515 };
516 int f(int x) {
517 S s;
518 return *s + x;
519 }
520 )cc";
521 const char *Ref = "ref";
522 TestMatch Match = matchCode(Code, Matcher: declRefExpr(to(InnerMatcher: functionDecl())).bind(ID: Ref));
523 EXPECT_THAT_EXPECTED(
524 name(Ref)(Match.Result),
525 Failed<StringError>(testing::Property(
526 &StringError::getMessage,
527 AllOf(HasSubstr(Ref), HasSubstr("requires property 'identifier'")))));
528}
529
530TEST(RangeSelectorTest, CallArgsOp) {
531 const StringRef Code = R"cc(
532 struct C {
533 int bar(int, int);
534 };
535 int f() {
536 C x;
537 return x.bar(3, 4);
538 }
539 )cc";
540 const char *ID = "id";
541 TestMatch Match = matchCode(Code, Matcher: callExpr().bind(ID));
542 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
543}
544
545TEST(RangeSelectorTest, CallArgsOpNoArgs) {
546 const StringRef Code = R"cc(
547 struct C {
548 int bar();
549 };
550 int f() {
551 C x;
552 return x.bar();
553 }
554 )cc";
555 const char *ID = "id";
556 TestMatch Match = matchCode(Code, Matcher: callExpr().bind(ID));
557 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(""));
558}
559
560TEST(RangeSelectorTest, CallArgsOpNoArgsWithComments) {
561 const StringRef Code = R"cc(
562 struct C {
563 int bar();
564 };
565 int f() {
566 C x;
567 return x.bar(/*empty*/);
568 }
569 )cc";
570 const char *ID = "id";
571 TestMatch Match = matchCode(Code, Matcher: callExpr().bind(ID));
572 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("/*empty*/"));
573}
574
575// Tests that arguments are extracted correctly when a temporary (with parens)
576// is used.
577TEST(RangeSelectorTest, CallArgsOpWithParens) {
578 const StringRef Code = R"cc(
579 struct C {
580 int bar(int, int) { return 3; }
581 };
582 int f() {
583 C x;
584 return C().bar(3, 4);
585 }
586 )cc";
587 const char *ID = "id";
588 TestMatch Match =
589 matchCode(Code, Matcher: callExpr(callee(InnerMatcher: functionDecl(hasName(Name: "bar")))).bind(ID));
590 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
591}
592
593TEST(RangeSelectorTest, CallArgsOpLeadingComments) {
594 const StringRef Code = R"cc(
595 struct C {
596 int bar(int, int) { return 3; }
597 };
598 int f() {
599 C x;
600 return x.bar(/*leading*/ 3, 4);
601 }
602 )cc";
603 const char *ID = "id";
604 TestMatch Match = matchCode(Code, Matcher: callExpr().bind(ID));
605 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
606 HasValue("/*leading*/ 3, 4"));
607}
608
609TEST(RangeSelectorTest, CallArgsOpTrailingComments) {
610 const StringRef Code = R"cc(
611 struct C {
612 int bar(int, int) { return 3; }
613 };
614 int f() {
615 C x;
616 return x.bar(3 /*trailing*/, 4);
617 }
618 )cc";
619 const char *ID = "id";
620 TestMatch Match = matchCode(Code, Matcher: callExpr().bind(ID));
621 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
622 HasValue("3 /*trailing*/, 4"));
623}
624
625TEST(RangeSelectorTest, CallArgsOpEolComments) {
626 const StringRef Code = R"cc(
627 struct C {
628 int bar(int, int) { return 3; }
629 };
630 int f() {
631 C x;
632 return x.bar( // Header
633 1, // foo
634 2 // bar
635 );
636 }
637 )cc";
638 const char *ID = "id";
639 TestMatch Match = matchCode(Code, Matcher: callExpr().bind(ID));
640 std::string ExpectedString = R"( // Header
641 1, // foo
642 2 // bar
643 )";
644 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(ExpectedString));
645}
646
647TEST(RangeSelectorTest, CallArgsErrors) {
648 EXPECT_THAT_EXPECTED(selectFromTrivial(callArgs("unbound_id")),
649 Failed<StringError>(withUnboundNodeMessage()));
650 EXPECT_THAT_EXPECTED(selectFromAssorted(callArgs("stmt")),
651 Failed<StringError>(withTypeErrorMessage("stmt")));
652}
653
654TEST(RangeSelectorTest, StatementsOp) {
655 StringRef Code = R"cc(
656 void g();
657 void f() { /* comment */ g(); /* comment */ g(); /* comment */ }
658 )cc";
659 const char *ID = "id";
660 TestMatch Match = matchCode(Code, Matcher: compoundStmt().bind(ID));
661 EXPECT_THAT_EXPECTED(
662 select(statements(ID), Match),
663 HasValue(" /* comment */ g(); /* comment */ g(); /* comment */ "));
664}
665
666TEST(RangeSelectorTest, StatementsOpEmptyList) {
667 StringRef Code = "void f() {}";
668 const char *ID = "id";
669 TestMatch Match = matchCode(Code, Matcher: compoundStmt().bind(ID));
670 EXPECT_THAT_EXPECTED(select(statements(ID), Match), HasValue(""));
671}
672
673TEST(RangeSelectorTest, StatementsOpErrors) {
674 EXPECT_THAT_EXPECTED(selectFromTrivial(statements("unbound_id")),
675 Failed<StringError>(withUnboundNodeMessage()));
676 EXPECT_THAT_EXPECTED(selectFromAssorted(statements("decl")),
677 Failed<StringError>(withTypeErrorMessage("decl")));
678}
679
680TEST(RangeSelectorTest, ElementsOp) {
681 StringRef Code = R"cc(
682 void f() {
683 int v[] = {/* comment */ 3, /* comment*/ 4 /* comment */};
684 (void)v;
685 }
686 )cc";
687 const char *ID = "id";
688 TestMatch Match = matchCode(Code, Matcher: initListExpr().bind(ID));
689 EXPECT_THAT_EXPECTED(
690 select(initListElements(ID), Match),
691 HasValue("/* comment */ 3, /* comment*/ 4 /* comment */"));
692}
693
694TEST(RangeSelectorTest, ElementsOpEmptyList) {
695 StringRef Code = R"cc(
696 void f() {
697 int v[] = {};
698 (void)v;
699 }
700 )cc";
701 const char *ID = "id";
702 TestMatch Match = matchCode(Code, Matcher: initListExpr().bind(ID));
703 EXPECT_THAT_EXPECTED(select(initListElements(ID), Match), HasValue(""));
704}
705
706TEST(RangeSelectorTest, ElementsOpErrors) {
707 EXPECT_THAT_EXPECTED(selectFromTrivial(initListElements("unbound_id")),
708 Failed<StringError>(withUnboundNodeMessage()));
709 EXPECT_THAT_EXPECTED(selectFromAssorted(initListElements("stmt")),
710 Failed<StringError>(withTypeErrorMessage("stmt")));
711}
712
713TEST(RangeSelectorTest, ElseBranchOpSingleStatement) {
714 StringRef Code = R"cc(
715 int f() {
716 int x = 0;
717 if (true) x = 3;
718 else x = 4;
719 return x + 5;
720 }
721 )cc";
722 const char *ID = "id";
723 TestMatch Match = matchCode(Code, Matcher: ifStmt().bind(ID));
724 EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), HasValue("else x = 4;"));
725}
726
727TEST(RangeSelectorTest, ElseBranchOpCompoundStatement) {
728 StringRef Code = R"cc(
729 int f() {
730 int x = 0;
731 if (true) x = 3;
732 else { x = 4; }
733 return x + 5;
734 }
735 )cc";
736 const char *ID = "id";
737 TestMatch Match = matchCode(Code, Matcher: ifStmt().bind(ID));
738 EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match),
739 HasValue("else { x = 4; }"));
740}
741
742// Tests case where the matched node is the complete expanded text.
743TEST(RangeSelectorTest, ExpansionOp) {
744 StringRef Code = R"cc(
745#define BADDECL(E) int bad(int x) { return E; }
746 BADDECL(x * x)
747 )cc";
748
749 const char *Fun = "Fun";
750 TestMatch Match = matchCode(Code, Matcher: functionDecl(hasName(Name: "bad")).bind(ID: Fun));
751 EXPECT_THAT_EXPECTED(select(expansion(node(Fun)), Match),
752 HasValue("BADDECL(x * x)"));
753}
754
755// Tests case where the matched node is (only) part of the expanded text.
756TEST(RangeSelectorTest, ExpansionOpPartial) {
757 StringRef Code = R"cc(
758#define BADDECL(E) int bad(int x) { return E; }
759 BADDECL(x * x)
760 )cc";
761
762 const char *Ret = "Ret";
763 TestMatch Match = matchCode(Code, Matcher: returnStmt().bind(ID: Ret));
764 EXPECT_THAT_EXPECTED(select(expansion(node(Ret)), Match),
765 HasValue("BADDECL(x * x)"));
766}
767
768TEST(RangeSelectorTest, IfBoundOpBound) {
769 StringRef Code = R"cc(
770 int f() {
771 return 3 + 5;
772 }
773 )cc";
774 const char *ID = "id", *Op = "op";
775 TestMatch Match =
776 matchCode(Code, Matcher: binaryOperator(hasLHS(InnerMatcher: expr().bind(ID))).bind(ID: Op));
777 EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),
778 HasValue("3"));
779}
780
781TEST(RangeSelectorTest, IfBoundOpUnbound) {
782 StringRef Code = R"cc(
783 int f() {
784 return 3 + 5;
785 }
786 )cc";
787 const char *ID = "id", *Op = "op";
788 TestMatch Match = matchCode(Code, Matcher: binaryOperator().bind(ID: Op));
789 EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),
790 HasValue("3 + 5"));
791}
792
793} // namespace
794

source code of clang/unittests/Tooling/RangeSelectorTest.cpp