1 //===- unittest/Tooling/StencilTest.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/Stencil.h" 10 #include "clang/AST/ASTTypeTraits.h" 11 #include "clang/AST/Expr.h" 12 #include "clang/ASTMatchers/ASTMatchers.h" 13 #include "clang/Tooling/FixIt.h" 14 #include "clang/Tooling/Tooling.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::Failed; 26 using ::llvm::HasValue; 27 using ::llvm::StringError; 28 using ::testing::AllOf; 29 using ::testing::HasSubstr; 30 using MatchResult = MatchFinder::MatchResult; 31 32 // Create a valid translation-unit from a statement. 33 static std::string wrapSnippet(StringRef ExtraPreface, 34 StringRef StatementCode) { 35 constexpr char Preface[] = R"cc( 36 namespace N { class C {}; } 37 namespace { class AnonC {}; } 38 struct S { int Field; }; 39 namespace std { 40 template <typename T> 41 struct unique_ptr { 42 T* operator->() const; 43 T& operator*() const; 44 }; 45 } 46 )cc"; 47 return (Preface + ExtraPreface + "auto stencil_test_snippet = []{" + 48 StatementCode + "};") 49 .str(); 50 } 51 52 static DeclarationMatcher wrapMatcher(const StatementMatcher &Matcher) { 53 return varDecl(hasName("stencil_test_snippet"), 54 hasDescendant(compoundStmt(hasAnySubstatement(Matcher)))); 55 } 56 57 struct TestMatch { 58 // The AST unit from which `result` is built. We bundle it because it backs 59 // the result. Users are not expected to access it. 60 std::unique_ptr<ASTUnit> AstUnit; 61 // The result to use in the test. References `ast_unit`. 62 MatchResult Result; 63 }; 64 65 // Matches `Matcher` against the statement `StatementCode` and returns the 66 // result. Handles putting the statement inside a function and modifying the 67 // matcher correspondingly. `Matcher` should match one of the statements in 68 // `StatementCode` exactly -- that is, produce exactly one match. However, 69 // `StatementCode` may contain other statements not described by `Matcher`. 70 // `ExtraPreface` (optionally) adds extra decls to the TU, before the code. 71 static llvm::Optional<TestMatch> matchStmt(StringRef StatementCode, 72 StatementMatcher Matcher, 73 StringRef ExtraPreface = "") { 74 auto AstUnit = tooling::buildASTFromCodeWithArgs( 75 wrapSnippet(ExtraPreface, StatementCode), {"-Wno-unused-value"}); 76 if (AstUnit == nullptr) { 77 ADD_FAILURE() << "AST construction failed"; 78 return llvm::None; 79 } 80 ASTContext &Context = AstUnit->getASTContext(); 81 auto Matches = ast_matchers::match(wrapMatcher(Matcher), Context); 82 // We expect a single, exact match for the statement. 83 if (Matches.size() != 1) { 84 ADD_FAILURE() << "Wrong number of matches: " << Matches.size(); 85 return llvm::None; 86 } 87 return TestMatch{std::move(AstUnit), MatchResult(Matches[0], &Context)}; 88 } 89 90 class StencilTest : public ::testing::Test { 91 protected: 92 // Verifies that the given stencil fails when evaluated on a valid match 93 // result. Binds a statement to "stmt", a (non-member) ctor-initializer to 94 // "init", an expression to "expr" and a (nameless) declaration to "decl". 95 void testError(const Stencil &Stencil, 96 ::testing::Matcher<std::string> Matcher) { 97 const std::string Snippet = R"cc( 98 struct A {}; 99 class F : public A { 100 public: 101 F(int) {} 102 }; 103 F(1); 104 )cc"; 105 auto StmtMatch = matchStmt( 106 Snippet, 107 stmt(hasDescendant( 108 cxxConstructExpr( 109 hasDeclaration(decl(hasDescendant(cxxCtorInitializer( 110 isBaseInitializer()) 111 .bind("init"))) 112 .bind("decl"))) 113 .bind("expr"))) 114 .bind("stmt")); 115 ASSERT_TRUE(StmtMatch); 116 if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) { 117 ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr; 118 } else { 119 auto Err = llvm::handleErrors(ResultOrErr.takeError(), 120 [&Matcher](const StringError &Err) { 121 EXPECT_THAT(Err.getMessage(), Matcher); 122 }); 123 if (Err) { 124 ADD_FAILURE() << "Unhandled error: " << llvm::toString(std::move(Err)); 125 } 126 } 127 } 128 129 // Tests failures caused by references to unbound nodes. `unbound_id` is the 130 // id that will cause the failure. 131 void testUnboundNodeError(const Stencil &Stencil, StringRef UnboundId) { 132 testError(Stencil, 133 AllOf(HasSubstr(std::string(UnboundId)), HasSubstr("not bound"))); 134 } 135 }; 136 137 TEST_F(StencilTest, SingleStatement) { 138 StringRef Condition("C"), Then("T"), Else("E"); 139 const std::string Snippet = R"cc( 140 if (true) 141 return 1; 142 else 143 return 0; 144 )cc"; 145 auto StmtMatch = matchStmt( 146 Snippet, ifStmt(hasCondition(expr().bind(Condition)), 147 hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else)))); 148 ASSERT_TRUE(StmtMatch); 149 // Invert the if-then-else. 150 auto Stencil = 151 cat("if (!", node(std::string(Condition)), ") ", 152 statement(std::string(Else)), " else ", statement(std::string(Then))); 153 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 154 HasValue("if (!true) return 0; else return 1;")); 155 } 156 157 TEST_F(StencilTest, UnboundNode) { 158 const std::string Snippet = R"cc( 159 if (true) 160 return 1; 161 else 162 return 0; 163 )cc"; 164 auto StmtMatch = matchStmt(Snippet, ifStmt(hasCondition(stmt().bind("a1")), 165 hasThen(stmt().bind("a2")))); 166 ASSERT_TRUE(StmtMatch); 167 auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";"); 168 auto ResultOrErr = Stencil->eval(StmtMatch->Result); 169 EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError())) 170 << "Expected unbound node, got " << *ResultOrErr; 171 } 172 173 // Tests that a stencil with a single parameter (`Id`) evaluates to the expected 174 // string, when `Id` is bound to the expression-statement in `Snippet`. 175 void testExpr(StringRef Id, StringRef Snippet, const Stencil &Stencil, 176 StringRef Expected) { 177 auto StmtMatch = matchStmt(Snippet, expr().bind(Id)); 178 ASSERT_TRUE(StmtMatch); 179 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 180 HasValue(std::string(Expected))); 181 } 182 183 void testFailure(StringRef Id, StringRef Snippet, const Stencil &Stencil, 184 testing::Matcher<std::string> MessageMatcher) { 185 auto StmtMatch = matchStmt(Snippet, expr().bind(Id)); 186 ASSERT_TRUE(StmtMatch); 187 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 188 Failed<StringError>(testing::Property( 189 &StringError::getMessage, MessageMatcher))); 190 } 191 192 TEST_F(StencilTest, SelectionOp) { 193 StringRef Id = "id"; 194 testExpr(Id, "3;", cat(node(std::string(Id))), "3"); 195 } 196 197 TEST_F(StencilTest, IfBoundOpBound) { 198 StringRef Id = "id"; 199 testExpr(Id, "3;", ifBound(Id, cat("5"), cat("7")), "5"); 200 } 201 202 TEST_F(StencilTest, IfBoundOpUnbound) { 203 StringRef Id = "id"; 204 testExpr(Id, "3;", ifBound("other", cat("5"), cat("7")), "7"); 205 } 206 207 static auto selectMatcher() { 208 // The `anything` matcher is not bound, to test for none of the cases 209 // matching. 210 return expr(anyOf(integerLiteral().bind("int"), cxxBoolLiteral().bind("bool"), 211 floatLiteral().bind("float"), anything())); 212 } 213 214 static auto selectStencil() { 215 return selectBound({ 216 {"int", cat("I")}, 217 {"bool", cat("B")}, 218 {"bool", cat("redundant")}, 219 {"float", cat("F")}, 220 }); 221 } 222 223 TEST_F(StencilTest, SelectBoundChooseDetectedMatch) { 224 std::string Input = "3;"; 225 auto StmtMatch = matchStmt(Input, selectMatcher()); 226 ASSERT_TRUE(StmtMatch); 227 EXPECT_THAT_EXPECTED(selectStencil()->eval(StmtMatch->Result), 228 HasValue(std::string("I"))); 229 } 230 231 TEST_F(StencilTest, SelectBoundChooseFirst) { 232 std::string Input = "true;"; 233 auto StmtMatch = matchStmt(Input, selectMatcher()); 234 ASSERT_TRUE(StmtMatch); 235 EXPECT_THAT_EXPECTED(selectStencil()->eval(StmtMatch->Result), 236 HasValue(std::string("B"))); 237 } 238 239 TEST_F(StencilTest, SelectBoundDiesOnExhaustedCases) { 240 std::string Input = "\"string\";"; 241 auto StmtMatch = matchStmt(Input, selectMatcher()); 242 ASSERT_TRUE(StmtMatch); 243 EXPECT_THAT_EXPECTED( 244 selectStencil()->eval(StmtMatch->Result), 245 Failed<StringError>(testing::Property( 246 &StringError::getMessage, 247 AllOf(HasSubstr("selectBound failed"), HasSubstr("no default"))))); 248 } 249 250 TEST_F(StencilTest, SelectBoundSucceedsWithDefault) { 251 std::string Input = "\"string\";"; 252 auto StmtMatch = matchStmt(Input, selectMatcher()); 253 ASSERT_TRUE(StmtMatch); 254 auto Stencil = selectBound({{"int", cat("I")}}, cat("D")); 255 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 256 HasValue(std::string("D"))); 257 } 258 259 TEST_F(StencilTest, ExpressionOpNoParens) { 260 StringRef Id = "id"; 261 testExpr(Id, "3;", expression(Id), "3"); 262 } 263 264 // Don't parenthesize a parens expression. 265 TEST_F(StencilTest, ExpressionOpNoParensParens) { 266 StringRef Id = "id"; 267 testExpr(Id, "(3);", expression(Id), "(3)"); 268 } 269 270 TEST_F(StencilTest, ExpressionOpBinaryOpParens) { 271 StringRef Id = "id"; 272 testExpr(Id, "3+4;", expression(Id), "(3+4)"); 273 } 274 275 // `expression` shares code with other ops, so we get sufficient coverage of the 276 // error handling code with this test. If that changes in the future, more error 277 // tests should be added. 278 TEST_F(StencilTest, ExpressionOpUnbound) { 279 StringRef Id = "id"; 280 testFailure(Id, "3;", expression("ACACA"), 281 AllOf(HasSubstr("ACACA"), HasSubstr("not bound"))); 282 } 283 284 TEST_F(StencilTest, DerefPointer) { 285 StringRef Id = "id"; 286 testExpr(Id, "int *x; x;", deref(Id), "*x"); 287 } 288 289 TEST_F(StencilTest, DerefBinOp) { 290 StringRef Id = "id"; 291 testExpr(Id, "int *x; x + 1;", deref(Id), "*(x + 1)"); 292 } 293 294 TEST_F(StencilTest, DerefAddressExpr) { 295 StringRef Id = "id"; 296 testExpr(Id, "int x; &x;", deref(Id), "x"); 297 } 298 299 TEST_F(StencilTest, AddressOfValue) { 300 StringRef Id = "id"; 301 testExpr(Id, "int x; x;", addressOf(Id), "&x"); 302 } 303 304 TEST_F(StencilTest, AddressOfDerefExpr) { 305 StringRef Id = "id"; 306 testExpr(Id, "int *x; *x;", addressOf(Id), "x"); 307 } 308 309 TEST_F(StencilTest, MaybeDerefValue) { 310 StringRef Id = "id"; 311 testExpr(Id, "int x; x;", maybeDeref(Id), "x"); 312 } 313 314 TEST_F(StencilTest, MaybeDerefPointer) { 315 StringRef Id = "id"; 316 testExpr(Id, "int *x; x;", maybeDeref(Id), "*x"); 317 } 318 319 TEST_F(StencilTest, MaybeDerefBinOp) { 320 StringRef Id = "id"; 321 testExpr(Id, "int *x; x + 1;", maybeDeref(Id), "*(x + 1)"); 322 } 323 324 TEST_F(StencilTest, MaybeDerefAddressExpr) { 325 StringRef Id = "id"; 326 testExpr(Id, "int x; &x;", maybeDeref(Id), "x"); 327 } 328 329 TEST_F(StencilTest, MaybeDerefSmartPointer) { 330 StringRef Id = "id"; 331 std::string Snippet = R"cc( 332 std::unique_ptr<S> x; 333 x; 334 )cc"; 335 testExpr(Id, Snippet, maybeDeref(Id), "*x"); 336 } 337 338 TEST_F(StencilTest, MaybeDerefSmartPointerFromMemberExpr) { 339 StringRef Id = "id"; 340 std::string Snippet = "std::unique_ptr<S> x; x->Field;"; 341 auto StmtMatch = 342 matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id)))); 343 ASSERT_TRUE(StmtMatch); 344 const Stencil Stencil = maybeDeref(Id); 345 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue("*x")); 346 } 347 348 TEST_F(StencilTest, MaybeAddressOfPointer) { 349 StringRef Id = "id"; 350 testExpr(Id, "int *x; x;", maybeAddressOf(Id), "x"); 351 } 352 353 TEST_F(StencilTest, MaybeAddressOfValue) { 354 StringRef Id = "id"; 355 testExpr(Id, "int x; x;", addressOf(Id), "&x"); 356 } 357 358 TEST_F(StencilTest, MaybeAddressOfBinOp) { 359 StringRef Id = "id"; 360 testExpr(Id, "int x; x + 1;", maybeAddressOf(Id), "&(x + 1)"); 361 } 362 363 TEST_F(StencilTest, MaybeAddressOfDerefExpr) { 364 StringRef Id = "id"; 365 testExpr(Id, "int *x; *x;", addressOf(Id), "x"); 366 } 367 368 TEST_F(StencilTest, MaybeAddressOfSmartPointer) { 369 StringRef Id = "id"; 370 testExpr(Id, "std::unique_ptr<S> x; x;", maybeAddressOf(Id), "x"); 371 } 372 373 TEST_F(StencilTest, MaybeAddressOfSmartPointerFromMemberCall) { 374 StringRef Id = "id"; 375 std::string Snippet = "std::unique_ptr<S> x; x->Field;"; 376 auto StmtMatch = 377 matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id)))); 378 ASSERT_TRUE(StmtMatch); 379 const Stencil Stencil = maybeAddressOf(Id); 380 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue("x")); 381 } 382 383 TEST_F(StencilTest, MaybeAddressOfSmartPointerDerefNoCancel) { 384 StringRef Id = "id"; 385 testExpr(Id, "std::unique_ptr<S> x; *x;", maybeAddressOf(Id), "&*x"); 386 } 387 388 TEST_F(StencilTest, AccessOpValue) { 389 StringRef Snippet = R"cc( 390 S x; 391 x; 392 )cc"; 393 StringRef Id = "id"; 394 testExpr(Id, Snippet, access(Id, "field"), "x.field"); 395 } 396 397 TEST_F(StencilTest, AccessOpValueExplicitText) { 398 StringRef Snippet = R"cc( 399 S x; 400 x; 401 )cc"; 402 StringRef Id = "id"; 403 testExpr(Id, Snippet, access(Id, cat("field")), "x.field"); 404 } 405 406 TEST_F(StencilTest, AccessOpValueAddress) { 407 StringRef Snippet = R"cc( 408 S x; 409 &x; 410 )cc"; 411 StringRef Id = "id"; 412 testExpr(Id, Snippet, access(Id, "field"), "x.field"); 413 } 414 415 TEST_F(StencilTest, AccessOpPointer) { 416 StringRef Snippet = R"cc( 417 S *x; 418 x; 419 )cc"; 420 StringRef Id = "id"; 421 testExpr(Id, Snippet, access(Id, "field"), "x->field"); 422 } 423 424 TEST_F(StencilTest, AccessOpPointerDereference) { 425 StringRef Snippet = R"cc( 426 S *x; 427 *x; 428 )cc"; 429 StringRef Id = "id"; 430 testExpr(Id, Snippet, access(Id, "field"), "x->field"); 431 } 432 433 TEST_F(StencilTest, AccessOpSmartPointer) { 434 StringRef Snippet = R"cc( 435 std::unique_ptr<S> x; 436 x; 437 )cc"; 438 StringRef Id = "id"; 439 testExpr(Id, Snippet, access(Id, "field"), "x->field"); 440 } 441 442 TEST_F(StencilTest, AccessOpSmartPointerDereference) { 443 StringRef Snippet = R"cc( 444 std::unique_ptr<S> x; 445 *x; 446 )cc"; 447 StringRef Id = "id"; 448 testExpr(Id, Snippet, access(Id, "field"), "x->field"); 449 } 450 451 TEST_F(StencilTest, AccessOpSmartPointerMemberCall) { 452 StringRef Snippet = R"cc( 453 std::unique_ptr<S> x; 454 x->Field; 455 )cc"; 456 StringRef Id = "id"; 457 auto StmtMatch = 458 matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id)))); 459 ASSERT_TRUE(StmtMatch); 460 EXPECT_THAT_EXPECTED(access(Id, "field")->eval(StmtMatch->Result), 461 HasValue("x->field")); 462 } 463 464 TEST_F(StencilTest, AccessOpExplicitThis) { 465 using clang::ast_matchers::hasObjectExpression; 466 using clang::ast_matchers::memberExpr; 467 468 // Set up the code so we can bind to a use of this. 469 StringRef Snippet = R"cc( 470 class C { 471 public: 472 int x; 473 int foo() { return this->x; } 474 }; 475 )cc"; 476 auto StmtMatch = matchStmt( 477 Snippet, 478 traverse(TK_AsIs, returnStmt(hasReturnValue(ignoringImplicit(memberExpr( 479 hasObjectExpression(expr().bind("obj")))))))); 480 ASSERT_TRUE(StmtMatch); 481 const Stencil Stencil = access("obj", "field"); 482 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 483 HasValue("this->field")); 484 } 485 486 TEST_F(StencilTest, AccessOpImplicitThis) { 487 using clang::ast_matchers::hasObjectExpression; 488 using clang::ast_matchers::memberExpr; 489 490 // Set up the code so we can bind to a use of (implicit) this. 491 StringRef Snippet = R"cc( 492 class C { 493 public: 494 int x; 495 int foo() { return x; } 496 }; 497 )cc"; 498 auto StmtMatch = 499 matchStmt(Snippet, returnStmt(hasReturnValue(ignoringImplicit(memberExpr( 500 hasObjectExpression(expr().bind("obj"))))))); 501 ASSERT_TRUE(StmtMatch); 502 const Stencil Stencil = access("obj", "field"); 503 EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue("field")); 504 } 505 506 TEST_F(StencilTest, DescribeType) { 507 std::string Snippet = "int *x; x;"; 508 std::string Expected = "int *"; 509 auto StmtMatch = 510 matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 511 ASSERT_TRUE(StmtMatch); 512 EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 513 HasValue(std::string(Expected))); 514 } 515 516 TEST_F(StencilTest, DescribeSugaredType) { 517 std::string Snippet = "using Ty = int; Ty *x; x;"; 518 std::string Expected = "Ty *"; 519 auto StmtMatch = 520 matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 521 ASSERT_TRUE(StmtMatch); 522 EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 523 HasValue(std::string(Expected))); 524 } 525 526 TEST_F(StencilTest, DescribeDeclType) { 527 std::string Snippet = "S s; s;"; 528 std::string Expected = "S"; 529 auto StmtMatch = 530 matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 531 ASSERT_TRUE(StmtMatch); 532 EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 533 HasValue(std::string(Expected))); 534 } 535 536 TEST_F(StencilTest, DescribeQualifiedType) { 537 std::string Snippet = "N::C c; c;"; 538 std::string Expected = "N::C"; 539 auto StmtMatch = 540 matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 541 ASSERT_TRUE(StmtMatch); 542 EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 543 HasValue(std::string(Expected))); 544 } 545 546 TEST_F(StencilTest, DescribeUnqualifiedType) { 547 std::string Snippet = "using N::C; C c; c;"; 548 std::string Expected = "N::C"; 549 auto StmtMatch = 550 matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 551 ASSERT_TRUE(StmtMatch); 552 EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 553 HasValue(std::string(Expected))); 554 } 555 556 TEST_F(StencilTest, DescribeAnonNamespaceType) { 557 std::string Snippet = "AnonC c; c;"; 558 std::string Expected = "(anonymous namespace)::AnonC"; 559 auto StmtMatch = 560 matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 561 ASSERT_TRUE(StmtMatch); 562 EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 563 HasValue(std::string(Expected))); 564 } 565 566 TEST_F(StencilTest, RunOp) { 567 StringRef Id = "id"; 568 auto SimpleFn = [Id](const MatchResult &R) { 569 return std::string(R.Nodes.getNodeAs<Stmt>(Id) != nullptr ? "Bound" 570 : "Unbound"); 571 }; 572 testExpr(Id, "3;", run(SimpleFn), "Bound"); 573 } 574 575 TEST_F(StencilTest, CatOfMacroRangeSucceeds) { 576 StringRef Snippet = R"cpp( 577 #define MACRO 3.77 578 double foo(double d); 579 foo(MACRO);)cpp"; 580 581 auto StmtMatch = 582 matchStmt(Snippet, callExpr(callee(functionDecl(hasName("foo"))), 583 argumentCountIs(1), 584 hasArgument(0, expr().bind("arg")))); 585 ASSERT_TRUE(StmtMatch); 586 Stencil S = cat(node("arg")); 587 EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("MACRO")); 588 } 589 590 TEST_F(StencilTest, CatOfMacroArgRangeSucceeds) { 591 StringRef Snippet = R"cpp( 592 #define MACRO(a, b) a + b 593 MACRO(2, 3);)cpp"; 594 595 auto StmtMatch = 596 matchStmt(Snippet, binaryOperator(hasRHS(expr().bind("rhs")))); 597 ASSERT_TRUE(StmtMatch); 598 Stencil S = cat(node("rhs")); 599 EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("3")); 600 } 601 602 TEST_F(StencilTest, CatOfMacroArgSubRangeSucceeds) { 603 StringRef Snippet = R"cpp( 604 #define MACRO(a, b) a + b 605 int foo(int); 606 MACRO(2, foo(3));)cpp"; 607 608 auto StmtMatch = matchStmt( 609 Snippet, binaryOperator(hasRHS(callExpr( 610 callee(functionDecl(hasName("foo"))), argumentCountIs(1), 611 hasArgument(0, expr().bind("arg")))))); 612 ASSERT_TRUE(StmtMatch); 613 Stencil S = cat(node("arg")); 614 EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("3")); 615 } 616 617 TEST_F(StencilTest, CatOfInvalidRangeFails) { 618 StringRef Snippet = R"cpp( 619 #define MACRO (3.77) 620 double foo(double d); 621 foo(MACRO);)cpp"; 622 623 auto StmtMatch = 624 matchStmt(Snippet, callExpr(callee(functionDecl(hasName("foo"))), 625 argumentCountIs(1), 626 hasArgument(0, expr().bind("arg")))); 627 ASSERT_TRUE(StmtMatch); 628 Stencil S = cat(node("arg")); 629 Expected<std::string> Result = S->eval(StmtMatch->Result); 630 ASSERT_FALSE(Result); 631 llvm::handleAllErrors(Result.takeError(), [](const llvm::StringError &E) { 632 EXPECT_THAT(E.getMessage(), AllOf(HasSubstr("selected range"), 633 HasSubstr("macro expansion"))); 634 }); 635 } 636 637 // The `StencilToStringTest` tests verify that the string representation of the 638 // stencil combinator matches (as best possible) the spelling of the 639 // combinator's construction. Exceptions include those combinators that have no 640 // explicit spelling (like raw text) and those supporting non-printable 641 // arguments (like `run`, `selection`). 642 643 TEST(StencilToStringTest, RawTextOp) { 644 auto S = cat("foo bar baz"); 645 StringRef Expected = R"("foo bar baz")"; 646 EXPECT_EQ(S->toString(), Expected); 647 } 648 649 TEST(StencilToStringTest, RawTextOpEscaping) { 650 auto S = cat("foo \"bar\" baz\\n"); 651 StringRef Expected = R"("foo \"bar\" baz\\n")"; 652 EXPECT_EQ(S->toString(), Expected); 653 } 654 655 TEST(StencilToStringTest, DescribeOp) { 656 auto S = describe("Id"); 657 StringRef Expected = R"repr(describe("Id"))repr"; 658 EXPECT_EQ(S->toString(), Expected); 659 } 660 661 TEST(StencilToStringTest, DebugPrintNodeOp) { 662 auto S = dPrint("Id"); 663 StringRef Expected = R"repr(dPrint("Id"))repr"; 664 EXPECT_EQ(S->toString(), Expected); 665 } 666 667 TEST(StencilToStringTest, ExpressionOp) { 668 auto S = expression("Id"); 669 StringRef Expected = R"repr(expression("Id"))repr"; 670 EXPECT_EQ(S->toString(), Expected); 671 } 672 673 TEST(StencilToStringTest, DerefOp) { 674 auto S = deref("Id"); 675 StringRef Expected = R"repr(deref("Id"))repr"; 676 EXPECT_EQ(S->toString(), Expected); 677 } 678 679 TEST(StencilToStringTest, AddressOfOp) { 680 auto S = addressOf("Id"); 681 StringRef Expected = R"repr(addressOf("Id"))repr"; 682 EXPECT_EQ(S->toString(), Expected); 683 } 684 685 TEST(StencilToStringTest, SelectionOp) { 686 auto S1 = cat(node("node1")); 687 EXPECT_EQ(S1->toString(), "selection(...)"); 688 } 689 690 TEST(StencilToStringTest, AccessOpText) { 691 auto S = access("Id", "memberData"); 692 StringRef Expected = R"repr(access("Id", "memberData"))repr"; 693 EXPECT_EQ(S->toString(), Expected); 694 } 695 696 TEST(StencilToStringTest, AccessOpSelector) { 697 auto S = access("Id", cat(name("otherId"))); 698 StringRef Expected = R"repr(access("Id", selection(...)))repr"; 699 EXPECT_EQ(S->toString(), Expected); 700 } 701 702 TEST(StencilToStringTest, AccessOpStencil) { 703 auto S = access("Id", cat("foo_", "bar")); 704 StringRef Expected = R"repr(access("Id", seq("foo_", "bar")))repr"; 705 EXPECT_EQ(S->toString(), Expected); 706 } 707 708 TEST(StencilToStringTest, IfBoundOp) { 709 auto S = ifBound("Id", cat("trueText"), access("exprId", "memberData")); 710 StringRef Expected = 711 R"repr(ifBound("Id", "trueText", access("exprId", "memberData")))repr"; 712 EXPECT_EQ(S->toString(), Expected); 713 } 714 715 TEST(StencilToStringTest, SelectBoundOp) { 716 auto S = selectBound({ 717 {"int", cat("I")}, 718 {"float", cat("F")}, 719 }); 720 StringRef Expected = R"repr(selectBound({{"int", "I"}, {"float", "F"}}))repr"; 721 EXPECT_EQ(S->toString(), Expected); 722 } 723 724 TEST(StencilToStringTest, SelectBoundOpWithOneCase) { 725 auto S = selectBound({{"int", cat("I")}}); 726 StringRef Expected = R"repr(selectBound({{"int", "I"}}))repr"; 727 EXPECT_EQ(S->toString(), Expected); 728 } 729 730 TEST(StencilToStringTest, SelectBoundOpWithDefault) { 731 auto S = selectBound({{"int", cat("I")}, {"float", cat("F")}}, cat("D")); 732 StringRef Expected = 733 R"cc(selectBound({{"int", "I"}, {"float", "F"}}, "D"))cc"; 734 EXPECT_EQ(S->toString(), Expected); 735 } 736 737 TEST(StencilToStringTest, RunOp) { 738 auto F1 = [](const MatchResult &R) { return "foo"; }; 739 auto S1 = run(F1); 740 EXPECT_EQ(S1->toString(), "run(...)"); 741 } 742 743 TEST(StencilToStringTest, Sequence) { 744 auto S = cat("foo", access("x", "m()"), "bar", 745 ifBound("x", cat("t"), access("e", "f"))); 746 StringRef Expected = R"repr(seq("foo", access("x", "m()"), "bar", )repr" 747 R"repr(ifBound("x", "t", access("e", "f"))))repr"; 748 EXPECT_EQ(S->toString(), Expected); 749 } 750 751 TEST(StencilToStringTest, SequenceEmpty) { 752 auto S = cat(); 753 StringRef Expected = "seq()"; 754 EXPECT_EQ(S->toString(), Expected); 755 } 756 757 TEST(StencilToStringTest, SequenceSingle) { 758 auto S = cat("foo"); 759 StringRef Expected = "\"foo\""; 760 EXPECT_EQ(S->toString(), Expected); 761 } 762 763 TEST(StencilToStringTest, SequenceFromVector) { 764 auto S = catVector({cat("foo"), access("x", "m()"), cat("bar"), 765 ifBound("x", cat("t"), access("e", "f"))}); 766 StringRef Expected = R"repr(seq("foo", access("x", "m()"), "bar", )repr" 767 R"repr(ifBound("x", "t", access("e", "f"))))repr"; 768 EXPECT_EQ(S->toString(), Expected); 769 } 770 } // namespace 771