953 lines · cpp
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-exception6//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 backs36 // 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{std::move(ASTUnit), 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, *Match.Result.Context);64}65 66// Applies \p Selector to a trivial match with only a single bound node with id67// "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 a70 // binding that is not used in the unbound node tests.71 TestMatch Match =72 matchCode("static int x = 0;", varDecl().bind("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 &StringError::getMessage,80 AllOf(HasSubstr("unbound_id"), HasSubstr("not bound")));81}82 83// Applies \p Selector to code containing assorted node types, where the match84// binds each one: a statement ("stmt"), a (non-member) ctor-initializer85// ("init"), an expression ("expr") and a (nameless) declaration ("decl"). Used86// 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 decl(hasDescendant(cxxCtorInitializer(isBaseInitializer())103 .bind("init")))104 .bind("decl")))105 .bind("expr")))106 .bind("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 &StringError::getMessage,115 AllOf(HasSubstr(NodeID), HasSubstr("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 mark129// 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(CallID);137 RangeSelector R = before(node(CallID.str()));138 139 TestMatch Match = matchCode(Code, M);140 const auto *E = Match.Result.Nodes.getNodeAs<Expr>(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(CallID);156 auto R = parseRangeSelector(R"rs(before(node("call")))rs");157 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());158 159 TestMatch Match = matchCode(Code, M);160 const auto *E = Match.Result.Nodes.getNodeAs<Expr>(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, callExpr().bind(Call));176 const auto* E = Match.Result.Nodes.getNodeAs<Expr>(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(1);182 const auto ExpectedAfter = CharSourceRange::getCharRange(SemiLoc, SemiLoc);183 184 // Test with a char range.185 auto CharRange = CharSourceRange::getCharRange(Range.getBegin(), 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(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 node196// `Id`.197static SourceLocation getSpellingLocAfter(const MatchResult &Result,198 StringRef Id, int Length) {199 const auto *E = Result.Nodes.getNodeAs<Expr>(Id);200 assert(E != nullptr);201 return Result.SourceManager->getSpellingLoc(E->getBeginLoc())202 .getLocWithOffset(Length);203}204 205// Test with a range that is the entire macro arg, but does not end the206// expansion itself.207TEST(RangeSelectorTest, AfterOpInMacroArg) {208 StringRef Code = R"cc(209#define ISNULL(x) x == nullptr210 bool g() { int* y; return ISNULL(y); }211 )cc";212 213 TestMatch Match =214 matchCode(Code, declRefExpr(to(namedDecl(hasName("y")))).bind("yvar"));215 int YVarLen = 1;216 SourceLocation After = getSpellingLocAfter(Match.Result, "yvar", YVarLen);217 CharSourceRange Expected = CharSourceRange::getCharRange(After, 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 == x226 bool g() { int* y; return ISNULL(y); }227 )cc";228 229 TestMatch Match =230 matchCode(Code, declRefExpr(to(namedDecl(hasName("y")))).bind("yvar"));231 int YVarLen = 1;232 SourceLocation After = getSpellingLocAfter(Match.Result, "yvar", YVarLen);233 CharSourceRange Expected = CharSourceRange::getCharRange(After, 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 == nullptr241 int* f(int*);242 bool g() { int* y; return ISNULL(f(y)); }243 )cc";244 245 TestMatch Match =246 matchCode(Code, declRefExpr(to(namedDecl(hasName("y")))).bind("yvar"));247 int YVarLen = 1;248 SourceLocation After = getSpellingLocAfter(Match.Result, "yvar", YVarLen);249 CharSourceRange Expected = CharSourceRange::getCharRange(After, 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(0, expr().bind("a0")),260 hasArgument(1, expr().bind("a1")));261 RangeSelector R = between(node("a0"), node("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(0, expr().bind("a0")),272 hasArgument(1, expr().bind("a1")));273 auto R = parseRangeSelector(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(0, expr().bind("a0")),286 hasArgument(1, expr().bind("a1")));287 RangeSelector R = encloseNodes("a0", "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(0, expr().bind("a0")),298 hasArgument(1, expr().bind("a1")));299 RangeSelector R = enclose(node("a0"), node("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(0, expr().bind("a0")),310 hasArgument(1, expr().bind("a1")));311 auto R = parseRangeSelector(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(0, expr().bind("a0")),323 hasArgument(1, expr().bind("a1")));324 auto R = parseRangeSelector(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, MergeOp) {331 StringRef Code = R"cc(332 int f(int x, int y, int z) { return 3; }333 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }334 )cc";335 auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),336 hasArgument(1, expr().bind("a1")),337 hasArgument(2, expr().bind("a2")));338 RangeSelector R = merge(node("a0"), node("a1"));339 TestMatch Match = matchCode(Code, Matcher);340 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, 7"));341 // Test the merge of two non-contiguous and out-of-order token-ranges.342 R = merge(node("a2"), node("a0"));343 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, 7 /* comment */, 9"));344 // Test the merge of a token-range (expr node) with a char-range (before).345 R = merge(node("a1"), before(node("a0")));346 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, 7"));347 // Test the merge of two char-ranges.348 R = merge(before(node("a0")), before(node("a1")));349 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3, "));350}351 352TEST(RangeSelectorTest, MergeOpParsed) {353 StringRef Code = R"cc(354 int f(int x, int y, int z) { return 3; }355 int g() { return f(/* comment */ 3, 7 /* comment */, 9); }356 )cc";357 auto Matcher = callExpr(hasArgument(0, expr().bind("a0")),358 hasArgument(1, expr().bind("a1")),359 hasArgument(2, expr().bind("a2")));360 auto R = parseRangeSelector(R"rs(merge(node("a0"), node("a1")))rs");361 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());362 TestMatch Match = matchCode(Code, Matcher);363 EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3, 7"));364 R = parseRangeSelector(R"rs(merge(node("a2"), node("a1")))rs");365 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());366 EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("7 /* comment */, 9"));367}368 369TEST(RangeSelectorTest, NodeOpStatement) {370 StringRef Code = "int f() { return 3; }";371 TestMatch Match = matchCode(Code, returnStmt().bind("id"));372 EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("return 3;"));373}374 375TEST(RangeSelectorTest, NodeOpExpression) {376 StringRef Code = "int f() { return 3; }";377 TestMatch Match = matchCode(Code, expr().bind("id"));378 EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("3"));379}380 381TEST(RangeSelectorTest, NodeOpTypeLoc) {382 StringRef Code = "namespace ns {struct Foo{};} ns::Foo a;";383 TestMatch Match =384 matchCode(Code, varDecl(hasTypeLoc(typeLoc().bind("typeloc"))));385 EXPECT_THAT_EXPECTED(select(node("typeloc"), Match), HasValue("ns::Foo"));386}387 388TEST(RangeSelectorTest, StatementOp) {389 StringRef Code = "int f() { return 3; }";390 TestMatch Match = matchCode(Code, expr().bind("id"));391 RangeSelector R = statement("id");392 EXPECT_THAT_EXPECTED(select(R, Match), HasValue("3;"));393}394 395TEST(RangeSelectorTest, StatementOpParsed) {396 StringRef Code = "int f() { return 3; }";397 TestMatch Match = matchCode(Code, expr().bind("id"));398 auto R = parseRangeSelector(R"rs(statement("id"))rs");399 ASSERT_THAT_EXPECTED(R, llvm::Succeeded());400 EXPECT_THAT_EXPECTED(select(*R, Match), HasValue("3;"));401}402 403TEST(RangeSelectorTest, MemberOp) {404 StringRef Code = R"cc(405 struct S {406 int member;407 };408 int g() {409 S s;410 return s.member;411 }412 )cc";413 const char *ID = "id";414 TestMatch Match = matchCode(Code, memberExpr().bind(ID));415 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));416}417 418// Tests that member does not select any qualifiers on the member name.419TEST(RangeSelectorTest, MemberOpQualified) {420 StringRef Code = R"cc(421 struct S {422 int member;423 };424 struct T : public S {425 int field;426 };427 int g() {428 T t;429 return t.S::member;430 }431 )cc";432 const char *ID = "id";433 TestMatch Match = matchCode(Code, memberExpr().bind(ID));434 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));435}436 437TEST(RangeSelectorTest, MemberOpTemplate) {438 StringRef Code = R"cc(439 struct S {440 template <typename T> T foo(T t);441 };442 int f(int x) {443 S s;444 return s.template foo<int>(3);445 }446 )cc";447 448 const char *ID = "id";449 TestMatch Match = matchCode(Code, memberExpr().bind(ID));450 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("foo"));451}452 453TEST(RangeSelectorTest, MemberOpOperator) {454 StringRef Code = R"cc(455 struct S {456 int operator*();457 };458 int f(int x) {459 S s;460 return s.operator *();461 }462 )cc";463 464 const char *ID = "id";465 TestMatch Match = matchCode(Code, memberExpr().bind(ID));466 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("operator *"));467}468 469TEST(RangeSelectorTest, NameOpNamedDecl) {470 StringRef Code = R"cc(471 int myfun() {472 return 3;473 }474 )cc";475 const char *ID = "id";476 TestMatch Match = matchCode(Code, functionDecl().bind(ID));477 EXPECT_THAT_EXPECTED(select(name(ID), Match), HasValue("myfun"));478}479 480TEST(RangeSelectorTest, NameOpDeclRef) {481 StringRef Code = R"cc(482 int foo(int x) {483 return x;484 }485 int g(int x) { return foo(x) * x; }486 )cc";487 const char *Ref = "ref";488 TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));489 EXPECT_THAT_EXPECTED(select(name(Ref), Match), HasValue("foo"));490}491 492TEST(RangeSelectorTest, NameOpCtorInitializer) {493 StringRef Code = R"cc(494 class C {495 public:496 C() : field(3) {}497 int field;498 };499 )cc";500 const char *Init = "init";501 TestMatch Match = matchCode(Code, cxxCtorInitializer().bind(Init));502 EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field"));503}504 505TEST(RangeSelectorTest, NameOpTypeLoc) {506 StringRef Code = R"cc(507 namespace ns {508 struct Foo {509 Foo();510 Foo(int);511 Foo(int, int);512 };513 } // namespace ns514 515 ns::Foo a;516 auto b = ns::Foo(3);517 auto c = ns::Foo(1, 2);518 )cc";519 const char *CtorTy = "ctor_ty";520 // Matches declaration of `a`521 TestMatch MatchA = matchCode(522 Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(CtorTy))));523 EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchA), HasValue("ns::Foo"));524 // Matches call of Foo(int)525 TestMatch MatchB = matchCode(526 Code, cxxFunctionalCastExpr(hasTypeLoc(typeLoc().bind(CtorTy))));527 EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchB), HasValue("ns::Foo"));528 // Matches call of Foo(int, int)529 TestMatch MatchC = matchCode(530 Code, cxxTemporaryObjectExpr(hasTypeLoc(typeLoc().bind(CtorTy))));531 EXPECT_THAT_EXPECTED(select(name(CtorTy), MatchC), HasValue("ns::Foo"));532}533 534TEST(RangeSelectorTest, NameOpTemplateSpecializationTypeLoc) {535 StringRef Code = R"cc(536 namespace ns {537 template <typename T>538 struct Foo {};539 } // namespace ns540 541 ns::Foo<int> a;542 )cc";543 const char *Loc = "tyloc";544 // Matches declaration of `a`.545 TestMatch MatchA =546 matchCode(Code, varDecl(hasName("a"), hasTypeLoc(typeLoc().bind(Loc))));547 EXPECT_THAT_EXPECTED(select(name(Loc), MatchA), HasValue("Foo"));548}549 550TEST(RangeSelectorTest, NameOpErrors) {551 EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")),552 Failed<StringError>(withUnboundNodeMessage()));553 EXPECT_THAT_EXPECTED(selectFromAssorted(name("stmt")),554 Failed<StringError>(withTypeErrorMessage("stmt")));555}556 557TEST(RangeSelectorTest, NameOpDeclRefError) {558 StringRef Code = R"cc(559 struct S {560 int operator*();561 };562 int f(int x) {563 S s;564 return *s + x;565 }566 )cc";567 const char *Ref = "ref";568 TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));569 EXPECT_THAT_EXPECTED(570 name(Ref)(Match.Result),571 Failed<StringError>(testing::Property(572 &StringError::getMessage,573 AllOf(HasSubstr(Ref), HasSubstr("requires property 'identifier'")))));574}575 576TEST(RangeSelectorTest, NameOpDeclInMacroArg) {577 StringRef Code = R"cc(578 #define MACRO(name) int name;579 MACRO(x)580 )cc";581 const char *ID = "id";582 TestMatch Match = matchCode(Code, varDecl().bind(ID));583 EXPECT_THAT_EXPECTED(select(name(ID), Match), HasValue("x"));584}585 586TEST(RangeSelectorTest, NameOpDeclInMacroBodyError) {587 StringRef Code = R"cc(588 #define MACRO int x;589 MACRO590 )cc";591 const char *ID = "id";592 TestMatch Match = matchCode(Code, varDecl().bind(ID));593 EXPECT_THAT_EXPECTED(594 name(ID)(Match.Result),595 Failed<StringError>(testing::Property(596 &StringError::getMessage,597 AllOf(HasSubstr("range selected by name(node id="),598 HasSubstr("' is different from decl name 'x'")))));599}600 601TEST(RangeSelectorTest, CallArgsOp) {602 const StringRef Code = R"cc(603 struct C {604 int bar(int, int);605 };606 int f() {607 C x;608 return x.bar(3, 4);609 }610 )cc";611 const char *ID = "id";612 TestMatch Match = matchCode(Code, callExpr().bind(ID));613 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));614}615 616TEST(RangeSelectorTest, CallArgsOpNoArgs) {617 const StringRef Code = R"cc(618 struct C {619 int bar();620 };621 int f() {622 C x;623 return x.bar();624 }625 )cc";626 const char *ID = "id";627 TestMatch Match = matchCode(Code, callExpr().bind(ID));628 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(""));629}630 631TEST(RangeSelectorTest, CallArgsOpNoArgsWithComments) {632 const StringRef Code = R"cc(633 struct C {634 int bar();635 };636 int f() {637 C x;638 return x.bar(/*empty*/);639 }640 )cc";641 const char *ID = "id";642 TestMatch Match = matchCode(Code, callExpr().bind(ID));643 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("/*empty*/"));644}645 646// Tests that arguments are extracted correctly when a temporary (with parens)647// is used.648TEST(RangeSelectorTest, CallArgsOpWithParens) {649 const StringRef Code = R"cc(650 struct C {651 int bar(int, int) { return 3; }652 };653 int f() {654 C x;655 return C().bar(3, 4);656 }657 )cc";658 const char *ID = "id";659 TestMatch Match =660 matchCode(Code, callExpr(callee(functionDecl(hasName("bar")))).bind(ID));661 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));662}663 664TEST(RangeSelectorTest, CallArgsOpLeadingComments) {665 const StringRef Code = R"cc(666 struct C {667 int bar(int, int) { return 3; }668 };669 int f() {670 C x;671 return x.bar(/*leading*/ 3, 4);672 }673 )cc";674 const char *ID = "id";675 TestMatch Match = matchCode(Code, callExpr().bind(ID));676 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),677 HasValue("/*leading*/ 3, 4"));678}679 680TEST(RangeSelectorTest, CallArgsOpTrailingComments) {681 const StringRef Code = R"cc(682 struct C {683 int bar(int, int) { return 3; }684 };685 int f() {686 C x;687 return x.bar(3 /*trailing*/, 4);688 }689 )cc";690 const char *ID = "id";691 TestMatch Match = matchCode(Code, callExpr().bind(ID));692 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),693 HasValue("3 /*trailing*/, 4"));694}695 696TEST(RangeSelectorTest, CallArgsOpEolComments) {697 const StringRef Code = R"cc(698 struct C {699 int bar(int, int) { return 3; }700 };701 int f() {702 C x;703 return x.bar( // Header704 1, // foo705 2 // bar706 );707 }708 )cc";709 const char *ID = "id";710 TestMatch Match = matchCode(Code, callExpr().bind(ID));711 std::string ExpectedString = R"( // Header712 1, // foo713 2 // bar714 )";715 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(ExpectedString));716}717 718TEST(RangeSelectorTest, CallArgsErrors) {719 EXPECT_THAT_EXPECTED(selectFromTrivial(callArgs("unbound_id")),720 Failed<StringError>(withUnboundNodeMessage()));721 EXPECT_THAT_EXPECTED(selectFromAssorted(callArgs("stmt")),722 Failed<StringError>(withTypeErrorMessage("stmt")));723}724 725TEST(RangeSelectorTest, ConstructExprArgs) {726 const StringRef Code = R"cc(727 struct C {728 C(int, int);729 };730 C f() {731 return C(1, 2);732 }733 )cc";734 const char *ID = "id";735 TestMatch Match = matchCode(Code, cxxTemporaryObjectExpr().bind(ID));736 EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2"));737}738 739TEST(RangeSelectorTest, ConstructExprBracedArgs) {740 const StringRef Code = R"cc(741 struct C {742 C(int, int);743 };744 C f() {745 return {1, 2};746 }747 )cc";748 const char *ID = "id";749 TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID));750 EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2"));751}752 753TEST(RangeSelectorTest, ConstructExprNoArgs) {754 const StringRef Code = R"cc(755 struct C {756 C();757 };758 C f() {759 return C();760 }761 )cc";762 const char *ID = "id";763 TestMatch Match = matchCode(Code, cxxTemporaryObjectExpr().bind(ID));764 EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue(""));765}766 767TEST(RangeSelectorTest, ConstructExprArgsDirectInitialization) {768 const StringRef Code = R"cc(769 struct C {770 C(int, int);771 };772 void f() {773 C c(1, 2);774 }775 )cc";776 const char *ID = "id";777 TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID));778 EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2"));779}780 781TEST(RangeSelectorTest, ConstructExprArgsDirectBraceInitialization) {782 const StringRef Code = R"cc(783 struct C {784 C(int, int);785 };786 void f() {787 C c{1, 2};788 }789 )cc";790 const char *ID = "id";791 TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID));792 EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2"));793}794 795TEST(RangeSelectorTest, ConstructExprArgsImplicitConstruction) {796 const StringRef Code = R"cc(797 struct C {798 C(int, int = 42);799 };800 void sink(C);801 void f() {802 sink(1);803 }804 )cc";805 const char *ID = "id";806 TestMatch Match = matchCode(807 Code,808 cxxConstructExpr(ignoringElidableConstructorCall(cxxConstructExpr()))809 .bind(ID));810 EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1"));811}812 813TEST(RangeSelectorTest, StatementsOp) {814 StringRef Code = R"cc(815 void g();816 void f() { /* comment */ g(); /* comment */ g(); /* comment */ }817 )cc";818 const char *ID = "id";819 TestMatch Match = matchCode(Code, compoundStmt().bind(ID));820 EXPECT_THAT_EXPECTED(821 select(statements(ID), Match),822 HasValue(" /* comment */ g(); /* comment */ g(); /* comment */ "));823}824 825TEST(RangeSelectorTest, StatementsOpEmptyList) {826 StringRef Code = "void f() {}";827 const char *ID = "id";828 TestMatch Match = matchCode(Code, compoundStmt().bind(ID));829 EXPECT_THAT_EXPECTED(select(statements(ID), Match), HasValue(""));830}831 832TEST(RangeSelectorTest, StatementsOpErrors) {833 EXPECT_THAT_EXPECTED(selectFromTrivial(statements("unbound_id")),834 Failed<StringError>(withUnboundNodeMessage()));835 EXPECT_THAT_EXPECTED(selectFromAssorted(statements("decl")),836 Failed<StringError>(withTypeErrorMessage("decl")));837}838 839TEST(RangeSelectorTest, ElementsOp) {840 StringRef Code = R"cc(841 void f() {842 int v[] = {/* comment */ 3, /* comment*/ 4 /* comment */};843 (void)v;844 }845 )cc";846 const char *ID = "id";847 TestMatch Match = matchCode(Code, initListExpr().bind(ID));848 EXPECT_THAT_EXPECTED(849 select(initListElements(ID), Match),850 HasValue("/* comment */ 3, /* comment*/ 4 /* comment */"));851}852 853TEST(RangeSelectorTest, ElementsOpEmptyList) {854 StringRef Code = R"cc(855 void f() {856 int v[] = {};857 (void)v;858 }859 )cc";860 const char *ID = "id";861 TestMatch Match = matchCode(Code, initListExpr().bind(ID));862 EXPECT_THAT_EXPECTED(select(initListElements(ID), Match), HasValue(""));863}864 865TEST(RangeSelectorTest, ElementsOpErrors) {866 EXPECT_THAT_EXPECTED(selectFromTrivial(initListElements("unbound_id")),867 Failed<StringError>(withUnboundNodeMessage()));868 EXPECT_THAT_EXPECTED(selectFromAssorted(initListElements("stmt")),869 Failed<StringError>(withTypeErrorMessage("stmt")));870}871 872TEST(RangeSelectorTest, ElseBranchOpSingleStatement) {873 StringRef Code = R"cc(874 int f() {875 int x = 0;876 if (true) x = 3;877 else x = 4;878 return x + 5;879 }880 )cc";881 const char *ID = "id";882 TestMatch Match = matchCode(Code, ifStmt().bind(ID));883 EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), HasValue("else x = 4;"));884}885 886TEST(RangeSelectorTest, ElseBranchOpCompoundStatement) {887 StringRef Code = R"cc(888 int f() {889 int x = 0;890 if (true) x = 3;891 else { x = 4; }892 return x + 5;893 }894 )cc";895 const char *ID = "id";896 TestMatch Match = matchCode(Code, ifStmt().bind(ID));897 EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match),898 HasValue("else { x = 4; }"));899}900 901// Tests case where the matched node is the complete expanded text.902TEST(RangeSelectorTest, ExpansionOp) {903 StringRef Code = R"cc(904#define BADDECL(E) int bad(int x) { return E; }905 BADDECL(x * x)906 )cc";907 908 const char *Fun = "Fun";909 TestMatch Match = matchCode(Code, functionDecl(hasName("bad")).bind(Fun));910 EXPECT_THAT_EXPECTED(select(expansion(node(Fun)), Match),911 HasValue("BADDECL(x * x)"));912}913 914// Tests case where the matched node is (only) part of the expanded text.915TEST(RangeSelectorTest, ExpansionOpPartial) {916 StringRef Code = R"cc(917#define BADDECL(E) int bad(int x) { return E; }918 BADDECL(x * x)919 )cc";920 921 const char *Ret = "Ret";922 TestMatch Match = matchCode(Code, returnStmt().bind(Ret));923 EXPECT_THAT_EXPECTED(select(expansion(node(Ret)), Match),924 HasValue("BADDECL(x * x)"));925}926 927TEST(RangeSelectorTest, IfBoundOpBound) {928 StringRef Code = R"cc(929 int f() {930 return 3 + 5;931 }932 )cc";933 const char *ID = "id", *Op = "op";934 TestMatch Match =935 matchCode(Code, binaryOperator(hasLHS(expr().bind(ID))).bind(Op));936 EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),937 HasValue("3"));938}939 940TEST(RangeSelectorTest, IfBoundOpUnbound) {941 StringRef Code = R"cc(942 int f() {943 return 3 + 5;944 }945 )cc";946 const char *ID = "id", *Op = "op";947 TestMatch Match = matchCode(Code, binaryOperator().bind(Op));948 EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match),949 HasValue("3 + 5"));950}951 952} // namespace953