1e955f8baSYitzhak Mandelbaum //===- unittest/Tooling/StencilTest.cpp -----------------------------------===// 2e955f8baSYitzhak Mandelbaum // 3e955f8baSYitzhak Mandelbaum // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e955f8baSYitzhak Mandelbaum // See https://llvm.org/LICENSE.txt for license information. 5e955f8baSYitzhak Mandelbaum // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e955f8baSYitzhak Mandelbaum // 7e955f8baSYitzhak Mandelbaum //===----------------------------------------------------------------------===// 8e955f8baSYitzhak Mandelbaum 9fbdf8352SYitzhak Mandelbaum #include "clang/Tooling/Transformer/Stencil.h" 10d81d69f1SYitzhak Mandelbaum #include "clang/AST/ASTTypeTraits.h" 11675a2973SYitzhak Mandelbaum #include "clang/AST/Expr.h" 12e955f8baSYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchers.h" 13e955f8baSYitzhak Mandelbaum #include "clang/Tooling/FixIt.h" 14e955f8baSYitzhak Mandelbaum #include "clang/Tooling/Tooling.h" 150a81b4edSYitzhak Mandelbaum #include "llvm/Support/Error.h" 160a81b4edSYitzhak Mandelbaum #include "llvm/Testing/Support/Error.h" 17e955f8baSYitzhak Mandelbaum #include "gmock/gmock.h" 18e955f8baSYitzhak Mandelbaum #include "gtest/gtest.h" 19a1580d7bSKazu Hirata #include <optional> 20e955f8baSYitzhak Mandelbaum 21e955f8baSYitzhak Mandelbaum using namespace clang; 228bb47cd8SYitzhak Mandelbaum using namespace transformer; 23e955f8baSYitzhak Mandelbaum using namespace ast_matchers; 24e955f8baSYitzhak Mandelbaum 25e955f8baSYitzhak Mandelbaum namespace { 26e80e8896SYitzhak Mandelbaum using ::llvm::Failed; 270a81b4edSYitzhak Mandelbaum using ::llvm::HasValue; 28e80e8896SYitzhak Mandelbaum using ::llvm::StringError; 29e955f8baSYitzhak Mandelbaum using ::testing::AllOf; 30e955f8baSYitzhak Mandelbaum using ::testing::HasSubstr; 31e955f8baSYitzhak Mandelbaum using MatchResult = MatchFinder::MatchResult; 32e955f8baSYitzhak Mandelbaum 33e955f8baSYitzhak Mandelbaum // Create a valid translation-unit from a statement. 34675a2973SYitzhak Mandelbaum static std::string wrapSnippet(StringRef ExtraPreface, 35675a2973SYitzhak Mandelbaum StringRef StatementCode) { 36675a2973SYitzhak Mandelbaum constexpr char Preface[] = R"cc( 37675a2973SYitzhak Mandelbaum namespace N { class C {}; } 38675a2973SYitzhak Mandelbaum namespace { class AnonC {}; } 39675a2973SYitzhak Mandelbaum struct S { int Field; }; 400944c196SYitzhak Mandelbaum namespace std { 410944c196SYitzhak Mandelbaum template <typename T> 420944c196SYitzhak Mandelbaum struct unique_ptr { 430944c196SYitzhak Mandelbaum T* operator->() const; 440944c196SYitzhak Mandelbaum T& operator*() const; 45675a2973SYitzhak Mandelbaum }; 460944c196SYitzhak Mandelbaum } 4715f3cd6bSMatheus Izvekov template<class T> T desugar() { return T(); }; 48675a2973SYitzhak Mandelbaum )cc"; 49675a2973SYitzhak Mandelbaum return (Preface + ExtraPreface + "auto stencil_test_snippet = []{" + 500a81b4edSYitzhak Mandelbaum StatementCode + "};") 510a81b4edSYitzhak Mandelbaum .str(); 52e955f8baSYitzhak Mandelbaum } 53e955f8baSYitzhak Mandelbaum 54e955f8baSYitzhak Mandelbaum static DeclarationMatcher wrapMatcher(const StatementMatcher &Matcher) { 55e955f8baSYitzhak Mandelbaum return varDecl(hasName("stencil_test_snippet"), 56e955f8baSYitzhak Mandelbaum hasDescendant(compoundStmt(hasAnySubstatement(Matcher)))); 57e955f8baSYitzhak Mandelbaum } 58e955f8baSYitzhak Mandelbaum 59e955f8baSYitzhak Mandelbaum struct TestMatch { 60e955f8baSYitzhak Mandelbaum // The AST unit from which `result` is built. We bundle it because it backs 61e955f8baSYitzhak Mandelbaum // the result. Users are not expected to access it. 62e955f8baSYitzhak Mandelbaum std::unique_ptr<ASTUnit> AstUnit; 63e955f8baSYitzhak Mandelbaum // The result to use in the test. References `ast_unit`. 64e955f8baSYitzhak Mandelbaum MatchResult Result; 65e955f8baSYitzhak Mandelbaum }; 66e955f8baSYitzhak Mandelbaum 67e955f8baSYitzhak Mandelbaum // Matches `Matcher` against the statement `StatementCode` and returns the 68e955f8baSYitzhak Mandelbaum // result. Handles putting the statement inside a function and modifying the 690a81b4edSYitzhak Mandelbaum // matcher correspondingly. `Matcher` should match one of the statements in 700a81b4edSYitzhak Mandelbaum // `StatementCode` exactly -- that is, produce exactly one match. However, 710a81b4edSYitzhak Mandelbaum // `StatementCode` may contain other statements not described by `Matcher`. 72675a2973SYitzhak Mandelbaum // `ExtraPreface` (optionally) adds extra decls to the TU, before the code. 736ad0788cSKazu Hirata static std::optional<TestMatch> matchStmt(StringRef StatementCode, 74675a2973SYitzhak Mandelbaum StatementMatcher Matcher, 75675a2973SYitzhak Mandelbaum StringRef ExtraPreface = "") { 76675a2973SYitzhak Mandelbaum auto AstUnit = tooling::buildASTFromCodeWithArgs( 77675a2973SYitzhak Mandelbaum wrapSnippet(ExtraPreface, StatementCode), {"-Wno-unused-value"}); 78e955f8baSYitzhak Mandelbaum if (AstUnit == nullptr) { 79e955f8baSYitzhak Mandelbaum ADD_FAILURE() << "AST construction failed"; 80a41fbb1fSKazu Hirata return std::nullopt; 81e955f8baSYitzhak Mandelbaum } 82e955f8baSYitzhak Mandelbaum ASTContext &Context = AstUnit->getASTContext(); 83e6bc4a71SYitzhak Mandelbaum auto Matches = ast_matchers::match(wrapMatcher(Matcher), Context); 84e955f8baSYitzhak Mandelbaum // We expect a single, exact match for the statement. 85e955f8baSYitzhak Mandelbaum if (Matches.size() != 1) { 86e955f8baSYitzhak Mandelbaum ADD_FAILURE() << "Wrong number of matches: " << Matches.size(); 87a41fbb1fSKazu Hirata return std::nullopt; 88e955f8baSYitzhak Mandelbaum } 89e955f8baSYitzhak Mandelbaum return TestMatch{std::move(AstUnit), MatchResult(Matches[0], &Context)}; 90e955f8baSYitzhak Mandelbaum } 91e955f8baSYitzhak Mandelbaum 92e955f8baSYitzhak Mandelbaum class StencilTest : public ::testing::Test { 93e955f8baSYitzhak Mandelbaum protected: 94e955f8baSYitzhak Mandelbaum // Verifies that the given stencil fails when evaluated on a valid match 95e955f8baSYitzhak Mandelbaum // result. Binds a statement to "stmt", a (non-member) ctor-initializer to 96e955f8baSYitzhak Mandelbaum // "init", an expression to "expr" and a (nameless) declaration to "decl". 97e955f8baSYitzhak Mandelbaum void testError(const Stencil &Stencil, 98e955f8baSYitzhak Mandelbaum ::testing::Matcher<std::string> Matcher) { 99e955f8baSYitzhak Mandelbaum const std::string Snippet = R"cc( 100e955f8baSYitzhak Mandelbaum struct A {}; 101e955f8baSYitzhak Mandelbaum class F : public A { 102e955f8baSYitzhak Mandelbaum public: 103e955f8baSYitzhak Mandelbaum F(int) {} 104e955f8baSYitzhak Mandelbaum }; 105e955f8baSYitzhak Mandelbaum F(1); 106e955f8baSYitzhak Mandelbaum )cc"; 107e955f8baSYitzhak Mandelbaum auto StmtMatch = matchStmt( 108e955f8baSYitzhak Mandelbaum Snippet, 109e955f8baSYitzhak Mandelbaum stmt(hasDescendant( 110e955f8baSYitzhak Mandelbaum cxxConstructExpr( 111e955f8baSYitzhak Mandelbaum hasDeclaration(decl(hasDescendant(cxxCtorInitializer( 112e955f8baSYitzhak Mandelbaum isBaseInitializer()) 113e955f8baSYitzhak Mandelbaum .bind("init"))) 114e955f8baSYitzhak Mandelbaum .bind("decl"))) 115e955f8baSYitzhak Mandelbaum .bind("expr"))) 116e955f8baSYitzhak Mandelbaum .bind("stmt")); 117e955f8baSYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 118ce2b5cb6SYitzhak Mandelbaum if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) { 119e955f8baSYitzhak Mandelbaum ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr; 120e955f8baSYitzhak Mandelbaum } else { 121e955f8baSYitzhak Mandelbaum auto Err = llvm::handleErrors(ResultOrErr.takeError(), 122e80e8896SYitzhak Mandelbaum [&Matcher](const StringError &Err) { 123e955f8baSYitzhak Mandelbaum EXPECT_THAT(Err.getMessage(), Matcher); 124e955f8baSYitzhak Mandelbaum }); 125e955f8baSYitzhak Mandelbaum if (Err) { 126e955f8baSYitzhak Mandelbaum ADD_FAILURE() << "Unhandled error: " << llvm::toString(std::move(Err)); 127e955f8baSYitzhak Mandelbaum } 128e955f8baSYitzhak Mandelbaum } 129e955f8baSYitzhak Mandelbaum } 130e955f8baSYitzhak Mandelbaum 131e955f8baSYitzhak Mandelbaum // Tests failures caused by references to unbound nodes. `unbound_id` is the 132e955f8baSYitzhak Mandelbaum // id that will cause the failure. 1330a81b4edSYitzhak Mandelbaum void testUnboundNodeError(const Stencil &Stencil, StringRef UnboundId) { 134adcd0268SBenjamin Kramer testError(Stencil, 135adcd0268SBenjamin Kramer AllOf(HasSubstr(std::string(UnboundId)), HasSubstr("not bound"))); 136e955f8baSYitzhak Mandelbaum } 137e955f8baSYitzhak Mandelbaum }; 138e955f8baSYitzhak Mandelbaum 139e955f8baSYitzhak Mandelbaum TEST_F(StencilTest, SingleStatement) { 140e955f8baSYitzhak Mandelbaum StringRef Condition("C"), Then("T"), Else("E"); 141e955f8baSYitzhak Mandelbaum const std::string Snippet = R"cc( 142e955f8baSYitzhak Mandelbaum if (true) 143e955f8baSYitzhak Mandelbaum return 1; 144e955f8baSYitzhak Mandelbaum else 145e955f8baSYitzhak Mandelbaum return 0; 146e955f8baSYitzhak Mandelbaum )cc"; 147e955f8baSYitzhak Mandelbaum auto StmtMatch = matchStmt( 148e955f8baSYitzhak Mandelbaum Snippet, ifStmt(hasCondition(expr().bind(Condition)), 149e955f8baSYitzhak Mandelbaum hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else)))); 150e955f8baSYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 151e955f8baSYitzhak Mandelbaum // Invert the if-then-else. 152adcd0268SBenjamin Kramer auto Stencil = 153adcd0268SBenjamin Kramer cat("if (!", node(std::string(Condition)), ") ", 154adcd0268SBenjamin Kramer statement(std::string(Else)), " else ", statement(std::string(Then))); 155ce2b5cb6SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 156185f56bbSYitzhak Mandelbaum HasValue("if (!true) return 0; else return 1;")); 157e955f8baSYitzhak Mandelbaum } 158e955f8baSYitzhak Mandelbaum 159e955f8baSYitzhak Mandelbaum TEST_F(StencilTest, UnboundNode) { 160e955f8baSYitzhak Mandelbaum const std::string Snippet = R"cc( 161e955f8baSYitzhak Mandelbaum if (true) 162e955f8baSYitzhak Mandelbaum return 1; 163e955f8baSYitzhak Mandelbaum else 164e955f8baSYitzhak Mandelbaum return 0; 165e955f8baSYitzhak Mandelbaum )cc"; 166e955f8baSYitzhak Mandelbaum auto StmtMatch = matchStmt(Snippet, ifStmt(hasCondition(stmt().bind("a1")), 167e955f8baSYitzhak Mandelbaum hasThen(stmt().bind("a2")))); 168e955f8baSYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 1691f46d524SYitzhak Mandelbaum auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";"); 170ce2b5cb6SYitzhak Mandelbaum auto ResultOrErr = Stencil->eval(StmtMatch->Result); 171e955f8baSYitzhak Mandelbaum EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError())) 172e955f8baSYitzhak Mandelbaum << "Expected unbound node, got " << *ResultOrErr; 173e955f8baSYitzhak Mandelbaum } 174e955f8baSYitzhak Mandelbaum 175e955f8baSYitzhak Mandelbaum // Tests that a stencil with a single parameter (`Id`) evaluates to the expected 176e955f8baSYitzhak Mandelbaum // string, when `Id` is bound to the expression-statement in `Snippet`. 177e955f8baSYitzhak Mandelbaum void testExpr(StringRef Id, StringRef Snippet, const Stencil &Stencil, 178e955f8baSYitzhak Mandelbaum StringRef Expected) { 179e955f8baSYitzhak Mandelbaum auto StmtMatch = matchStmt(Snippet, expr().bind(Id)); 180e955f8baSYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 181adcd0268SBenjamin Kramer EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 182adcd0268SBenjamin Kramer HasValue(std::string(Expected))); 183e955f8baSYitzhak Mandelbaum } 184e955f8baSYitzhak Mandelbaum 185e80e8896SYitzhak Mandelbaum void testFailure(StringRef Id, StringRef Snippet, const Stencil &Stencil, 186e80e8896SYitzhak Mandelbaum testing::Matcher<std::string> MessageMatcher) { 187e80e8896SYitzhak Mandelbaum auto StmtMatch = matchStmt(Snippet, expr().bind(Id)); 188e80e8896SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 189ce2b5cb6SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 190e80e8896SYitzhak Mandelbaum Failed<StringError>(testing::Property( 191e80e8896SYitzhak Mandelbaum &StringError::getMessage, MessageMatcher))); 192e80e8896SYitzhak Mandelbaum } 193e80e8896SYitzhak Mandelbaum 1941f46d524SYitzhak Mandelbaum TEST_F(StencilTest, SelectionOp) { 195e955f8baSYitzhak Mandelbaum StringRef Id = "id"; 196adcd0268SBenjamin Kramer testExpr(Id, "3;", cat(node(std::string(Id))), "3"); 197e955f8baSYitzhak Mandelbaum } 198e955f8baSYitzhak Mandelbaum 1990a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, IfBoundOpBound) { 2000a81b4edSYitzhak Mandelbaum StringRef Id = "id"; 20187340a2bSYitzhak Mandelbaum testExpr(Id, "3;", ifBound(Id, cat("5"), cat("7")), "5"); 2020a81b4edSYitzhak Mandelbaum } 2030a81b4edSYitzhak Mandelbaum 2040a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, IfBoundOpUnbound) { 2050a81b4edSYitzhak Mandelbaum StringRef Id = "id"; 20687340a2bSYitzhak Mandelbaum testExpr(Id, "3;", ifBound("other", cat("5"), cat("7")), "7"); 2070a81b4edSYitzhak Mandelbaum } 2080a81b4edSYitzhak Mandelbaum 209b6c218d4SYitzhak Mandelbaum static auto selectMatcher() { 210b6c218d4SYitzhak Mandelbaum // The `anything` matcher is not bound, to test for none of the cases 211b6c218d4SYitzhak Mandelbaum // matching. 212b6c218d4SYitzhak Mandelbaum return expr(anyOf(integerLiteral().bind("int"), cxxBoolLiteral().bind("bool"), 213b6c218d4SYitzhak Mandelbaum floatLiteral().bind("float"), anything())); 214b6c218d4SYitzhak Mandelbaum } 215b6c218d4SYitzhak Mandelbaum 216b6c218d4SYitzhak Mandelbaum static auto selectStencil() { 217b6c218d4SYitzhak Mandelbaum return selectBound({ 218b6c218d4SYitzhak Mandelbaum {"int", cat("I")}, 219b6c218d4SYitzhak Mandelbaum {"bool", cat("B")}, 220b6c218d4SYitzhak Mandelbaum {"bool", cat("redundant")}, 221b6c218d4SYitzhak Mandelbaum {"float", cat("F")}, 222b6c218d4SYitzhak Mandelbaum }); 223b6c218d4SYitzhak Mandelbaum } 224b6c218d4SYitzhak Mandelbaum 225b6c218d4SYitzhak Mandelbaum TEST_F(StencilTest, SelectBoundChooseDetectedMatch) { 226b6c218d4SYitzhak Mandelbaum std::string Input = "3;"; 227b6c218d4SYitzhak Mandelbaum auto StmtMatch = matchStmt(Input, selectMatcher()); 228b6c218d4SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 229b6c218d4SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(selectStencil()->eval(StmtMatch->Result), 230b6c218d4SYitzhak Mandelbaum HasValue(std::string("I"))); 231b6c218d4SYitzhak Mandelbaum } 232b6c218d4SYitzhak Mandelbaum 233b6c218d4SYitzhak Mandelbaum TEST_F(StencilTest, SelectBoundChooseFirst) { 234b6c218d4SYitzhak Mandelbaum std::string Input = "true;"; 235b6c218d4SYitzhak Mandelbaum auto StmtMatch = matchStmt(Input, selectMatcher()); 236b6c218d4SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 237b6c218d4SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(selectStencil()->eval(StmtMatch->Result), 238b6c218d4SYitzhak Mandelbaum HasValue(std::string("B"))); 239b6c218d4SYitzhak Mandelbaum } 240b6c218d4SYitzhak Mandelbaum 241b6c218d4SYitzhak Mandelbaum TEST_F(StencilTest, SelectBoundDiesOnExhaustedCases) { 242b6c218d4SYitzhak Mandelbaum std::string Input = "\"string\";"; 243b6c218d4SYitzhak Mandelbaum auto StmtMatch = matchStmt(Input, selectMatcher()); 244b6c218d4SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 245b6c218d4SYitzhak Mandelbaum EXPECT_THAT_EXPECTED( 246b6c218d4SYitzhak Mandelbaum selectStencil()->eval(StmtMatch->Result), 247b6c218d4SYitzhak Mandelbaum Failed<StringError>(testing::Property( 248b6c218d4SYitzhak Mandelbaum &StringError::getMessage, 249b6c218d4SYitzhak Mandelbaum AllOf(HasSubstr("selectBound failed"), HasSubstr("no default"))))); 250b6c218d4SYitzhak Mandelbaum } 251b6c218d4SYitzhak Mandelbaum 252b6c218d4SYitzhak Mandelbaum TEST_F(StencilTest, SelectBoundSucceedsWithDefault) { 253b6c218d4SYitzhak Mandelbaum std::string Input = "\"string\";"; 254b6c218d4SYitzhak Mandelbaum auto StmtMatch = matchStmt(Input, selectMatcher()); 255b6c218d4SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 256b6c218d4SYitzhak Mandelbaum auto Stencil = selectBound({{"int", cat("I")}}, cat("D")); 257b6c218d4SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 258b6c218d4SYitzhak Mandelbaum HasValue(std::string("D"))); 259b6c218d4SYitzhak Mandelbaum } 260b6c218d4SYitzhak Mandelbaum 261e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, ExpressionOpNoParens) { 262e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 263ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "3;", expression(Id), "3"); 264e80e8896SYitzhak Mandelbaum } 265e80e8896SYitzhak Mandelbaum 266e80e8896SYitzhak Mandelbaum // Don't parenthesize a parens expression. 267e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, ExpressionOpNoParensParens) { 268e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 269ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "(3);", expression(Id), "(3)"); 270e80e8896SYitzhak Mandelbaum } 271e80e8896SYitzhak Mandelbaum 272e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, ExpressionOpBinaryOpParens) { 273e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 274ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "3+4;", expression(Id), "(3+4)"); 275e80e8896SYitzhak Mandelbaum } 276e80e8896SYitzhak Mandelbaum 277e80e8896SYitzhak Mandelbaum // `expression` shares code with other ops, so we get sufficient coverage of the 278e80e8896SYitzhak Mandelbaum // error handling code with this test. If that changes in the future, more error 279e80e8896SYitzhak Mandelbaum // tests should be added. 280e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, ExpressionOpUnbound) { 281e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 282ce2b5cb6SYitzhak Mandelbaum testFailure(Id, "3;", expression("ACACA"), 283e80e8896SYitzhak Mandelbaum AllOf(HasSubstr("ACACA"), HasSubstr("not bound"))); 284e80e8896SYitzhak Mandelbaum } 285e80e8896SYitzhak Mandelbaum 286e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, DerefPointer) { 287e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 288ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "int *x; x;", deref(Id), "*x"); 289e80e8896SYitzhak Mandelbaum } 290e80e8896SYitzhak Mandelbaum 291e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, DerefBinOp) { 292e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 293ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "int *x; x + 1;", deref(Id), "*(x + 1)"); 294e80e8896SYitzhak Mandelbaum } 295e80e8896SYitzhak Mandelbaum 296e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, DerefAddressExpr) { 297e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 298ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "int x; &x;", deref(Id), "x"); 299e80e8896SYitzhak Mandelbaum } 300e80e8896SYitzhak Mandelbaum 301e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, AddressOfValue) { 302e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 303ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "int x; x;", addressOf(Id), "&x"); 304e80e8896SYitzhak Mandelbaum } 305e80e8896SYitzhak Mandelbaum 306e80e8896SYitzhak Mandelbaum TEST_F(StencilTest, AddressOfDerefExpr) { 307e80e8896SYitzhak Mandelbaum StringRef Id = "id"; 308ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "int *x; *x;", addressOf(Id), "x"); 309e80e8896SYitzhak Mandelbaum } 310e80e8896SYitzhak Mandelbaum 31101e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeDerefValue) { 31201e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 31301e8dd2eSYitzhak Mandelbaum testExpr(Id, "int x; x;", maybeDeref(Id), "x"); 31401e8dd2eSYitzhak Mandelbaum } 31501e8dd2eSYitzhak Mandelbaum 31601e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeDerefPointer) { 31701e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 31801e8dd2eSYitzhak Mandelbaum testExpr(Id, "int *x; x;", maybeDeref(Id), "*x"); 31901e8dd2eSYitzhak Mandelbaum } 32001e8dd2eSYitzhak Mandelbaum 32101e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeDerefBinOp) { 32201e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 32301e8dd2eSYitzhak Mandelbaum testExpr(Id, "int *x; x + 1;", maybeDeref(Id), "*(x + 1)"); 32401e8dd2eSYitzhak Mandelbaum } 32501e8dd2eSYitzhak Mandelbaum 32601e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeDerefAddressExpr) { 32701e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 32801e8dd2eSYitzhak Mandelbaum testExpr(Id, "int x; &x;", maybeDeref(Id), "x"); 32901e8dd2eSYitzhak Mandelbaum } 33001e8dd2eSYitzhak Mandelbaum 331675a2973SYitzhak Mandelbaum TEST_F(StencilTest, MaybeDerefSmartPointer) { 332675a2973SYitzhak Mandelbaum StringRef Id = "id"; 333675a2973SYitzhak Mandelbaum std::string Snippet = R"cc( 3340944c196SYitzhak Mandelbaum std::unique_ptr<S> x; 335675a2973SYitzhak Mandelbaum x; 336675a2973SYitzhak Mandelbaum )cc"; 337675a2973SYitzhak Mandelbaum testExpr(Id, Snippet, maybeDeref(Id), "*x"); 338675a2973SYitzhak Mandelbaum } 339675a2973SYitzhak Mandelbaum 340675a2973SYitzhak Mandelbaum TEST_F(StencilTest, MaybeDerefSmartPointerFromMemberExpr) { 341675a2973SYitzhak Mandelbaum StringRef Id = "id"; 3420944c196SYitzhak Mandelbaum std::string Snippet = "std::unique_ptr<S> x; x->Field;"; 343675a2973SYitzhak Mandelbaum auto StmtMatch = 344675a2973SYitzhak Mandelbaum matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id)))); 345675a2973SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 346675a2973SYitzhak Mandelbaum const Stencil Stencil = maybeDeref(Id); 347675a2973SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue("*x")); 348675a2973SYitzhak Mandelbaum } 349675a2973SYitzhak Mandelbaum 35001e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeAddressOfPointer) { 35101e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 35201e8dd2eSYitzhak Mandelbaum testExpr(Id, "int *x; x;", maybeAddressOf(Id), "x"); 35301e8dd2eSYitzhak Mandelbaum } 35401e8dd2eSYitzhak Mandelbaum 35501e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeAddressOfValue) { 35601e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 35701e8dd2eSYitzhak Mandelbaum testExpr(Id, "int x; x;", addressOf(Id), "&x"); 35801e8dd2eSYitzhak Mandelbaum } 35901e8dd2eSYitzhak Mandelbaum 36001e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeAddressOfBinOp) { 36101e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 36201e8dd2eSYitzhak Mandelbaum testExpr(Id, "int x; x + 1;", maybeAddressOf(Id), "&(x + 1)"); 36301e8dd2eSYitzhak Mandelbaum } 36401e8dd2eSYitzhak Mandelbaum 36501e8dd2eSYitzhak Mandelbaum TEST_F(StencilTest, MaybeAddressOfDerefExpr) { 36601e8dd2eSYitzhak Mandelbaum StringRef Id = "id"; 36701e8dd2eSYitzhak Mandelbaum testExpr(Id, "int *x; *x;", addressOf(Id), "x"); 36801e8dd2eSYitzhak Mandelbaum } 36901e8dd2eSYitzhak Mandelbaum 370675a2973SYitzhak Mandelbaum TEST_F(StencilTest, MaybeAddressOfSmartPointer) { 371675a2973SYitzhak Mandelbaum StringRef Id = "id"; 3720944c196SYitzhak Mandelbaum testExpr(Id, "std::unique_ptr<S> x; x;", maybeAddressOf(Id), "x"); 373675a2973SYitzhak Mandelbaum } 374675a2973SYitzhak Mandelbaum 375675a2973SYitzhak Mandelbaum TEST_F(StencilTest, MaybeAddressOfSmartPointerFromMemberCall) { 376675a2973SYitzhak Mandelbaum StringRef Id = "id"; 3770944c196SYitzhak Mandelbaum std::string Snippet = "std::unique_ptr<S> x; x->Field;"; 378675a2973SYitzhak Mandelbaum auto StmtMatch = 379675a2973SYitzhak Mandelbaum matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id)))); 380675a2973SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 381675a2973SYitzhak Mandelbaum const Stencil Stencil = maybeAddressOf(Id); 382675a2973SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue("x")); 383675a2973SYitzhak Mandelbaum } 384675a2973SYitzhak Mandelbaum 385675a2973SYitzhak Mandelbaum TEST_F(StencilTest, MaybeAddressOfSmartPointerDerefNoCancel) { 386675a2973SYitzhak Mandelbaum StringRef Id = "id"; 3870944c196SYitzhak Mandelbaum testExpr(Id, "std::unique_ptr<S> x; *x;", maybeAddressOf(Id), "&*x"); 388675a2973SYitzhak Mandelbaum } 389675a2973SYitzhak Mandelbaum 3900a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, AccessOpValue) { 3910a81b4edSYitzhak Mandelbaum StringRef Snippet = R"cc( 3920a81b4edSYitzhak Mandelbaum S x; 3930a81b4edSYitzhak Mandelbaum x; 3940a81b4edSYitzhak Mandelbaum )cc"; 3950a81b4edSYitzhak Mandelbaum StringRef Id = "id"; 396ce2b5cb6SYitzhak Mandelbaum testExpr(Id, Snippet, access(Id, "field"), "x.field"); 3970a81b4edSYitzhak Mandelbaum } 3980a81b4edSYitzhak Mandelbaum 3990a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, AccessOpValueExplicitText) { 4000a81b4edSYitzhak Mandelbaum StringRef Snippet = R"cc( 4010a81b4edSYitzhak Mandelbaum S x; 4020a81b4edSYitzhak Mandelbaum x; 4030a81b4edSYitzhak Mandelbaum )cc"; 4040a81b4edSYitzhak Mandelbaum StringRef Id = "id"; 40587340a2bSYitzhak Mandelbaum testExpr(Id, Snippet, access(Id, cat("field")), "x.field"); 4060a81b4edSYitzhak Mandelbaum } 4070a81b4edSYitzhak Mandelbaum 4080a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, AccessOpValueAddress) { 4090a81b4edSYitzhak Mandelbaum StringRef Snippet = R"cc( 4100a81b4edSYitzhak Mandelbaum S x; 4110a81b4edSYitzhak Mandelbaum &x; 4120a81b4edSYitzhak Mandelbaum )cc"; 4130a81b4edSYitzhak Mandelbaum StringRef Id = "id"; 414ce2b5cb6SYitzhak Mandelbaum testExpr(Id, Snippet, access(Id, "field"), "x.field"); 4150a81b4edSYitzhak Mandelbaum } 4160a81b4edSYitzhak Mandelbaum 4170a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, AccessOpPointer) { 4180a81b4edSYitzhak Mandelbaum StringRef Snippet = R"cc( 4190a81b4edSYitzhak Mandelbaum S *x; 4200a81b4edSYitzhak Mandelbaum x; 4210a81b4edSYitzhak Mandelbaum )cc"; 4220a81b4edSYitzhak Mandelbaum StringRef Id = "id"; 423ce2b5cb6SYitzhak Mandelbaum testExpr(Id, Snippet, access(Id, "field"), "x->field"); 4240a81b4edSYitzhak Mandelbaum } 4250a81b4edSYitzhak Mandelbaum 4260a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, AccessOpPointerDereference) { 4270a81b4edSYitzhak Mandelbaum StringRef Snippet = R"cc( 4280a81b4edSYitzhak Mandelbaum S *x; 4290a81b4edSYitzhak Mandelbaum *x; 4300a81b4edSYitzhak Mandelbaum )cc"; 4310a81b4edSYitzhak Mandelbaum StringRef Id = "id"; 432ce2b5cb6SYitzhak Mandelbaum testExpr(Id, Snippet, access(Id, "field"), "x->field"); 4330a81b4edSYitzhak Mandelbaum } 4340a81b4edSYitzhak Mandelbaum 4351c571722SShu-Chun Weng TEST_F(StencilTest, AccessOpSmartPointer) { 4361c571722SShu-Chun Weng StringRef Snippet = R"cc( 4370944c196SYitzhak Mandelbaum std::unique_ptr<S> x; 4381c571722SShu-Chun Weng x; 4391c571722SShu-Chun Weng )cc"; 4401c571722SShu-Chun Weng StringRef Id = "id"; 4411c571722SShu-Chun Weng testExpr(Id, Snippet, access(Id, "field"), "x->field"); 4421c571722SShu-Chun Weng } 4431c571722SShu-Chun Weng 4441c571722SShu-Chun Weng TEST_F(StencilTest, AccessOpSmartPointerDereference) { 4451c571722SShu-Chun Weng StringRef Snippet = R"cc( 4460944c196SYitzhak Mandelbaum std::unique_ptr<S> x; 4471c571722SShu-Chun Weng *x; 4481c571722SShu-Chun Weng )cc"; 4491c571722SShu-Chun Weng StringRef Id = "id"; 450c7ed4fe5SYitzhak Mandelbaum testExpr(Id, Snippet, access(Id, "field"), "x->field"); 4511c571722SShu-Chun Weng } 4521c571722SShu-Chun Weng 4531c571722SShu-Chun Weng TEST_F(StencilTest, AccessOpSmartPointerMemberCall) { 4541c571722SShu-Chun Weng StringRef Snippet = R"cc( 4550944c196SYitzhak Mandelbaum std::unique_ptr<S> x; 4561c571722SShu-Chun Weng x->Field; 4571c571722SShu-Chun Weng )cc"; 4581c571722SShu-Chun Weng StringRef Id = "id"; 4591c571722SShu-Chun Weng auto StmtMatch = 4601c571722SShu-Chun Weng matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id)))); 4611c571722SShu-Chun Weng ASSERT_TRUE(StmtMatch); 4621c571722SShu-Chun Weng EXPECT_THAT_EXPECTED(access(Id, "field")->eval(StmtMatch->Result), 4631c571722SShu-Chun Weng HasValue("x->field")); 4641c571722SShu-Chun Weng } 4651c571722SShu-Chun Weng 4660a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, AccessOpExplicitThis) { 4670a81b4edSYitzhak Mandelbaum using clang::ast_matchers::hasObjectExpression; 4680a81b4edSYitzhak Mandelbaum using clang::ast_matchers::memberExpr; 4690a81b4edSYitzhak Mandelbaum 4700a81b4edSYitzhak Mandelbaum // Set up the code so we can bind to a use of this. 4710a81b4edSYitzhak Mandelbaum StringRef Snippet = R"cc( 4720a81b4edSYitzhak Mandelbaum class C { 4730a81b4edSYitzhak Mandelbaum public: 4740a81b4edSYitzhak Mandelbaum int x; 4750a81b4edSYitzhak Mandelbaum int foo() { return this->x; } 4760a81b4edSYitzhak Mandelbaum }; 4770a81b4edSYitzhak Mandelbaum )cc"; 478a30d4116SStephen Kelly auto StmtMatch = matchStmt( 479027899daSAlexander Kornienko Snippet, 480027899daSAlexander Kornienko traverse(TK_AsIs, returnStmt(hasReturnValue(ignoringImplicit(memberExpr( 481a30d4116SStephen Kelly hasObjectExpression(expr().bind("obj")))))))); 4820a81b4edSYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 483ce2b5cb6SYitzhak Mandelbaum const Stencil Stencil = access("obj", "field"); 484ce2b5cb6SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), 4850a81b4edSYitzhak Mandelbaum HasValue("this->field")); 4860a81b4edSYitzhak Mandelbaum } 4870a81b4edSYitzhak Mandelbaum 4880a81b4edSYitzhak Mandelbaum TEST_F(StencilTest, AccessOpImplicitThis) { 4890a81b4edSYitzhak Mandelbaum using clang::ast_matchers::hasObjectExpression; 4900a81b4edSYitzhak Mandelbaum using clang::ast_matchers::memberExpr; 4910a81b4edSYitzhak Mandelbaum 4920a81b4edSYitzhak Mandelbaum // Set up the code so we can bind to a use of (implicit) this. 4930a81b4edSYitzhak Mandelbaum StringRef Snippet = R"cc( 4940a81b4edSYitzhak Mandelbaum class C { 4950a81b4edSYitzhak Mandelbaum public: 4960a81b4edSYitzhak Mandelbaum int x; 4970a81b4edSYitzhak Mandelbaum int foo() { return x; } 4980a81b4edSYitzhak Mandelbaum }; 4990a81b4edSYitzhak Mandelbaum )cc"; 5000a81b4edSYitzhak Mandelbaum auto StmtMatch = 5010a81b4edSYitzhak Mandelbaum matchStmt(Snippet, returnStmt(hasReturnValue(ignoringImplicit(memberExpr( 5020a81b4edSYitzhak Mandelbaum hasObjectExpression(expr().bind("obj"))))))); 5030a81b4edSYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 504ce2b5cb6SYitzhak Mandelbaum const Stencil Stencil = access("obj", "field"); 505ce2b5cb6SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue("field")); 5060a81b4edSYitzhak Mandelbaum } 5070a81b4edSYitzhak Mandelbaum 508e6bc4a71SYitzhak Mandelbaum TEST_F(StencilTest, DescribeType) { 509e6bc4a71SYitzhak Mandelbaum std::string Snippet = "int *x; x;"; 510e6bc4a71SYitzhak Mandelbaum std::string Expected = "int *"; 511e6bc4a71SYitzhak Mandelbaum auto StmtMatch = 512e6bc4a71SYitzhak Mandelbaum matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 513e6bc4a71SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 514e6bc4a71SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 515e6bc4a71SYitzhak Mandelbaum HasValue(std::string(Expected))); 516e6bc4a71SYitzhak Mandelbaum } 517e6bc4a71SYitzhak Mandelbaum 518e6bc4a71SYitzhak Mandelbaum TEST_F(StencilTest, DescribeSugaredType) { 519e6bc4a71SYitzhak Mandelbaum std::string Snippet = "using Ty = int; Ty *x; x;"; 520e6bc4a71SYitzhak Mandelbaum std::string Expected = "Ty *"; 521e6bc4a71SYitzhak Mandelbaum auto StmtMatch = 522e6bc4a71SYitzhak Mandelbaum matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 523e6bc4a71SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 524e6bc4a71SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 525e6bc4a71SYitzhak Mandelbaum HasValue(std::string(Expected))); 526e6bc4a71SYitzhak Mandelbaum } 527e6bc4a71SYitzhak Mandelbaum 528e6bc4a71SYitzhak Mandelbaum TEST_F(StencilTest, DescribeDeclType) { 529e6bc4a71SYitzhak Mandelbaum std::string Snippet = "S s; s;"; 530e6bc4a71SYitzhak Mandelbaum std::string Expected = "S"; 531e6bc4a71SYitzhak Mandelbaum auto StmtMatch = 532e6bc4a71SYitzhak Mandelbaum matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 533e6bc4a71SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 534e6bc4a71SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 535e6bc4a71SYitzhak Mandelbaum HasValue(std::string(Expected))); 536e6bc4a71SYitzhak Mandelbaum } 537e6bc4a71SYitzhak Mandelbaum 538e6bc4a71SYitzhak Mandelbaum TEST_F(StencilTest, DescribeQualifiedType) { 539e6bc4a71SYitzhak Mandelbaum std::string Snippet = "N::C c; c;"; 540e6bc4a71SYitzhak Mandelbaum std::string Expected = "N::C"; 541e6bc4a71SYitzhak Mandelbaum auto StmtMatch = 542e6bc4a71SYitzhak Mandelbaum matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 543e6bc4a71SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 544e6bc4a71SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 545e6bc4a71SYitzhak Mandelbaum HasValue(std::string(Expected))); 546e6bc4a71SYitzhak Mandelbaum } 547e6bc4a71SYitzhak Mandelbaum 548e6bc4a71SYitzhak Mandelbaum TEST_F(StencilTest, DescribeUnqualifiedType) { 549e6bc4a71SYitzhak Mandelbaum std::string Snippet = "using N::C; C c; c;"; 55015f3cd6bSMatheus Izvekov std::string Expected = "C"; 551e6bc4a71SYitzhak Mandelbaum auto StmtMatch = 552e6bc4a71SYitzhak Mandelbaum matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 553e6bc4a71SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 554e6bc4a71SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 555e6bc4a71SYitzhak Mandelbaum HasValue(std::string(Expected))); 556e6bc4a71SYitzhak Mandelbaum } 557e6bc4a71SYitzhak Mandelbaum 558e6bc4a71SYitzhak Mandelbaum TEST_F(StencilTest, DescribeAnonNamespaceType) { 55915f3cd6bSMatheus Izvekov std::string Snippet = "auto c = desugar<AnonC>(); c;"; 560e6bc4a71SYitzhak Mandelbaum std::string Expected = "(anonymous namespace)::AnonC"; 561e6bc4a71SYitzhak Mandelbaum auto StmtMatch = 562e6bc4a71SYitzhak Mandelbaum matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); 563e6bc4a71SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 564e6bc4a71SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(describe("type")->eval(StmtMatch->Result), 565e6bc4a71SYitzhak Mandelbaum HasValue(std::string(Expected))); 566e6bc4a71SYitzhak Mandelbaum } 567e6bc4a71SYitzhak Mandelbaum 568*512cecadSClement Courbet TEST_F(StencilTest, DescribeFunction) { 569*512cecadSClement Courbet std::string Snippet = "int F(); F();"; 570*512cecadSClement Courbet std::string Expected = "F"; 571*512cecadSClement Courbet auto StmtMatch = matchStmt(Snippet, callExpr(callee(namedDecl().bind("fn")))); 572*512cecadSClement Courbet ASSERT_TRUE(StmtMatch); 573*512cecadSClement Courbet EXPECT_THAT_EXPECTED(describe("fn")->eval(StmtMatch->Result), 574*512cecadSClement Courbet HasValue(std::string(Expected))); 575*512cecadSClement Courbet } 576*512cecadSClement Courbet 577*512cecadSClement Courbet TEST_F(StencilTest, DescribeImplicitOperator) { 578*512cecadSClement Courbet std::string Snippet = "struct Tag {}; [](Tag){};"; 579*512cecadSClement Courbet std::string Expected = "operator()"; 580*512cecadSClement Courbet auto StmtMatch = matchStmt( 581*512cecadSClement Courbet Snippet, 582*512cecadSClement Courbet stmt(hasDescendant( 583*512cecadSClement Courbet cxxMethodDecl(hasParameter(0, hasType(namedDecl(hasName("Tag"))))) 584*512cecadSClement Courbet .bind("fn")))); 585*512cecadSClement Courbet ASSERT_TRUE(StmtMatch); 586*512cecadSClement Courbet EXPECT_THAT_EXPECTED(describe("fn")->eval(StmtMatch->Result), 587*512cecadSClement Courbet HasValue(std::string(Expected))); 588*512cecadSClement Courbet } 589*512cecadSClement Courbet 590ea966c1bSYitzhak Mandelbaum TEST_F(StencilTest, RunOp) { 591ea966c1bSYitzhak Mandelbaum StringRef Id = "id"; 592ea966c1bSYitzhak Mandelbaum auto SimpleFn = [Id](const MatchResult &R) { 593ea966c1bSYitzhak Mandelbaum return std::string(R.Nodes.getNodeAs<Stmt>(Id) != nullptr ? "Bound" 594ea966c1bSYitzhak Mandelbaum : "Unbound"); 595ea966c1bSYitzhak Mandelbaum }; 596ce2b5cb6SYitzhak Mandelbaum testExpr(Id, "3;", run(SimpleFn), "Bound"); 597ea966c1bSYitzhak Mandelbaum } 598ea966c1bSYitzhak Mandelbaum 599d81d69f1SYitzhak Mandelbaum TEST_F(StencilTest, CatOfMacroRangeSucceeds) { 600d81d69f1SYitzhak Mandelbaum StringRef Snippet = R"cpp( 601d81d69f1SYitzhak Mandelbaum #define MACRO 3.77 602d81d69f1SYitzhak Mandelbaum double foo(double d); 603d81d69f1SYitzhak Mandelbaum foo(MACRO);)cpp"; 604d81d69f1SYitzhak Mandelbaum 605d81d69f1SYitzhak Mandelbaum auto StmtMatch = 606d81d69f1SYitzhak Mandelbaum matchStmt(Snippet, callExpr(callee(functionDecl(hasName("foo"))), 607d81d69f1SYitzhak Mandelbaum argumentCountIs(1), 608d81d69f1SYitzhak Mandelbaum hasArgument(0, expr().bind("arg")))); 609d81d69f1SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 610d81d69f1SYitzhak Mandelbaum Stencil S = cat(node("arg")); 611d81d69f1SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("MACRO")); 612d81d69f1SYitzhak Mandelbaum } 613d81d69f1SYitzhak Mandelbaum 614d81d69f1SYitzhak Mandelbaum TEST_F(StencilTest, CatOfMacroArgRangeSucceeds) { 615d81d69f1SYitzhak Mandelbaum StringRef Snippet = R"cpp( 616d81d69f1SYitzhak Mandelbaum #define MACRO(a, b) a + b 617d81d69f1SYitzhak Mandelbaum MACRO(2, 3);)cpp"; 618d81d69f1SYitzhak Mandelbaum 619d81d69f1SYitzhak Mandelbaum auto StmtMatch = 620d81d69f1SYitzhak Mandelbaum matchStmt(Snippet, binaryOperator(hasRHS(expr().bind("rhs")))); 621d81d69f1SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 622d81d69f1SYitzhak Mandelbaum Stencil S = cat(node("rhs")); 623d81d69f1SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("3")); 624d81d69f1SYitzhak Mandelbaum } 625d81d69f1SYitzhak Mandelbaum 626d81d69f1SYitzhak Mandelbaum TEST_F(StencilTest, CatOfMacroArgSubRangeSucceeds) { 627d81d69f1SYitzhak Mandelbaum StringRef Snippet = R"cpp( 628d81d69f1SYitzhak Mandelbaum #define MACRO(a, b) a + b 629d81d69f1SYitzhak Mandelbaum int foo(int); 630d81d69f1SYitzhak Mandelbaum MACRO(2, foo(3));)cpp"; 631d81d69f1SYitzhak Mandelbaum 632d81d69f1SYitzhak Mandelbaum auto StmtMatch = matchStmt( 633d81d69f1SYitzhak Mandelbaum Snippet, binaryOperator(hasRHS(callExpr( 634d81d69f1SYitzhak Mandelbaum callee(functionDecl(hasName("foo"))), argumentCountIs(1), 635d81d69f1SYitzhak Mandelbaum hasArgument(0, expr().bind("arg")))))); 636d81d69f1SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 637d81d69f1SYitzhak Mandelbaum Stencil S = cat(node("arg")); 638d81d69f1SYitzhak Mandelbaum EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("3")); 639d81d69f1SYitzhak Mandelbaum } 640d81d69f1SYitzhak Mandelbaum 641b9d2bf38SYitzhak Mandelbaum TEST_F(StencilTest, CatOfInvalidRangeFails) { 642b9d2bf38SYitzhak Mandelbaum StringRef Snippet = R"cpp( 643b9d2bf38SYitzhak Mandelbaum #define MACRO (3.77) 644b9d2bf38SYitzhak Mandelbaum double foo(double d); 645b9d2bf38SYitzhak Mandelbaum foo(MACRO);)cpp"; 646b9d2bf38SYitzhak Mandelbaum 647b9d2bf38SYitzhak Mandelbaum auto StmtMatch = 648b9d2bf38SYitzhak Mandelbaum matchStmt(Snippet, callExpr(callee(functionDecl(hasName("foo"))), 649b9d2bf38SYitzhak Mandelbaum argumentCountIs(1), 650b9d2bf38SYitzhak Mandelbaum hasArgument(0, expr().bind("arg")))); 651b9d2bf38SYitzhak Mandelbaum ASSERT_TRUE(StmtMatch); 652b9d2bf38SYitzhak Mandelbaum Stencil S = cat(node("arg")); 65330deabf8SYitzhak Mandelbaum Expected<std::string> Result = S->eval(StmtMatch->Result); 654bb78dd2eSPaul Robinson ASSERT_FALSE(Result); 65530deabf8SYitzhak Mandelbaum llvm::handleAllErrors(Result.takeError(), [](const llvm::StringError &E) { 65630deabf8SYitzhak Mandelbaum EXPECT_THAT(E.getMessage(), AllOf(HasSubstr("selected range"), 65730deabf8SYitzhak Mandelbaum HasSubstr("macro expansion"))); 65830deabf8SYitzhak Mandelbaum }); 659b9d2bf38SYitzhak Mandelbaum } 660b9d2bf38SYitzhak Mandelbaum 661e6bc4a71SYitzhak Mandelbaum // The `StencilToStringTest` tests verify that the string representation of the 662e6bc4a71SYitzhak Mandelbaum // stencil combinator matches (as best possible) the spelling of the 663e6bc4a71SYitzhak Mandelbaum // combinator's construction. Exceptions include those combinators that have no 664e6bc4a71SYitzhak Mandelbaum // explicit spelling (like raw text) and those supporting non-printable 665e6bc4a71SYitzhak Mandelbaum // arguments (like `run`, `selection`). 666e6bc4a71SYitzhak Mandelbaum 667d5b98355SYitzhak Mandelbaum TEST(StencilToStringTest, RawTextOp) { 668d5b98355SYitzhak Mandelbaum auto S = cat("foo bar baz"); 669e4cec2d3SYitzhak Mandelbaum StringRef Expected = R"("foo bar baz")"; 670ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 671d5b98355SYitzhak Mandelbaum } 672d5b98355SYitzhak Mandelbaum 673d5b98355SYitzhak Mandelbaum TEST(StencilToStringTest, RawTextOpEscaping) { 674d5b98355SYitzhak Mandelbaum auto S = cat("foo \"bar\" baz\\n"); 675e4cec2d3SYitzhak Mandelbaum StringRef Expected = R"("foo \"bar\" baz\\n")"; 676ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 677d5b98355SYitzhak Mandelbaum } 678d5b98355SYitzhak Mandelbaum 679e6bc4a71SYitzhak Mandelbaum TEST(StencilToStringTest, DescribeOp) { 680e6bc4a71SYitzhak Mandelbaum auto S = describe("Id"); 681e6bc4a71SYitzhak Mandelbaum StringRef Expected = R"repr(describe("Id"))repr"; 682e6bc4a71SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 683e6bc4a71SYitzhak Mandelbaum } 684e6bc4a71SYitzhak Mandelbaum 685d5b98355SYitzhak Mandelbaum TEST(StencilToStringTest, DebugPrintNodeOp) { 686ce2b5cb6SYitzhak Mandelbaum auto S = dPrint("Id"); 687e4cec2d3SYitzhak Mandelbaum StringRef Expected = R"repr(dPrint("Id"))repr"; 688ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 689d5b98355SYitzhak Mandelbaum } 690d5b98355SYitzhak Mandelbaum 691d5b98355SYitzhak Mandelbaum TEST(StencilToStringTest, ExpressionOp) { 692ce2b5cb6SYitzhak Mandelbaum auto S = expression("Id"); 693e4cec2d3SYitzhak Mandelbaum StringRef Expected = R"repr(expression("Id"))repr"; 694ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 695d5b98355SYitzhak Mandelbaum } 696d5b98355SYitzhak Mandelbaum 697d5b98355SYitzhak Mandelbaum TEST(StencilToStringTest, DerefOp) { 698ce2b5cb6SYitzhak Mandelbaum auto S = deref("Id"); 699e4cec2d3SYitzhak Mandelbaum StringRef Expected = R"repr(deref("Id"))repr"; 700ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 701d5b98355SYitzhak Mandelbaum } 702d5b98355SYitzhak Mandelbaum 703d5b98355SYitzhak Mandelbaum TEST(StencilToStringTest, AddressOfOp) { 704ce2b5cb6SYitzhak Mandelbaum auto S = addressOf("Id"); 705e4cec2d3SYitzhak Mandelbaum StringRef Expected = R"repr(addressOf("Id"))repr"; 706ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 707d5b98355SYitzhak Mandelbaum } 708d5b98355SYitzhak Mandelbaum 709cf2438ecSYitzhak Mandelbaum TEST(StencilToStringTest, SelectionOp) { 710cf2438ecSYitzhak Mandelbaum auto S1 = cat(node("node1")); 711ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S1->toString(), "selection(...)"); 712cf2438ecSYitzhak Mandelbaum } 713cf2438ecSYitzhak Mandelbaum 714ce2b5cb6SYitzhak Mandelbaum TEST(StencilToStringTest, AccessOpText) { 715ce2b5cb6SYitzhak Mandelbaum auto S = access("Id", "memberData"); 716e4cec2d3SYitzhak Mandelbaum StringRef Expected = R"repr(access("Id", "memberData"))repr"; 717ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 718d5b98355SYitzhak Mandelbaum } 719d5b98355SYitzhak Mandelbaum 720ce2b5cb6SYitzhak Mandelbaum TEST(StencilToStringTest, AccessOpSelector) { 72187340a2bSYitzhak Mandelbaum auto S = access("Id", cat(name("otherId"))); 722ce2b5cb6SYitzhak Mandelbaum StringRef Expected = R"repr(access("Id", selection(...)))repr"; 723ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 724ce2b5cb6SYitzhak Mandelbaum } 725ce2b5cb6SYitzhak Mandelbaum 726ce2b5cb6SYitzhak Mandelbaum TEST(StencilToStringTest, AccessOpStencil) { 727ce2b5cb6SYitzhak Mandelbaum auto S = access("Id", cat("foo_", "bar")); 728ce2b5cb6SYitzhak Mandelbaum StringRef Expected = R"repr(access("Id", seq("foo_", "bar")))repr"; 729ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 730d5b98355SYitzhak Mandelbaum } 731d5b98355SYitzhak Mandelbaum 732d5b98355SYitzhak Mandelbaum TEST(StencilToStringTest, IfBoundOp) { 73387340a2bSYitzhak Mandelbaum auto S = ifBound("Id", cat("trueText"), access("exprId", "memberData")); 734e4cec2d3SYitzhak Mandelbaum StringRef Expected = 735e4cec2d3SYitzhak Mandelbaum R"repr(ifBound("Id", "trueText", access("exprId", "memberData")))repr"; 736ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 737d5b98355SYitzhak Mandelbaum } 738d5b98355SYitzhak Mandelbaum 739b6c218d4SYitzhak Mandelbaum TEST(StencilToStringTest, SelectBoundOp) { 740b6c218d4SYitzhak Mandelbaum auto S = selectBound({ 741b6c218d4SYitzhak Mandelbaum {"int", cat("I")}, 742b6c218d4SYitzhak Mandelbaum {"float", cat("F")}, 743b6c218d4SYitzhak Mandelbaum }); 744b6c218d4SYitzhak Mandelbaum StringRef Expected = R"repr(selectBound({{"int", "I"}, {"float", "F"}}))repr"; 745b6c218d4SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 746b6c218d4SYitzhak Mandelbaum } 747b6c218d4SYitzhak Mandelbaum 748b6c218d4SYitzhak Mandelbaum TEST(StencilToStringTest, SelectBoundOpWithOneCase) { 749b6c218d4SYitzhak Mandelbaum auto S = selectBound({{"int", cat("I")}}); 750b6c218d4SYitzhak Mandelbaum StringRef Expected = R"repr(selectBound({{"int", "I"}}))repr"; 751b6c218d4SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 752b6c218d4SYitzhak Mandelbaum } 753b6c218d4SYitzhak Mandelbaum 754b6c218d4SYitzhak Mandelbaum TEST(StencilToStringTest, SelectBoundOpWithDefault) { 755b6c218d4SYitzhak Mandelbaum auto S = selectBound({{"int", cat("I")}, {"float", cat("F")}}, cat("D")); 756b6c218d4SYitzhak Mandelbaum StringRef Expected = 757b6c218d4SYitzhak Mandelbaum R"cc(selectBound({{"int", "I"}, {"float", "F"}}, "D"))cc"; 758b6c218d4SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 759b6c218d4SYitzhak Mandelbaum } 760b6c218d4SYitzhak Mandelbaum 761cf2438ecSYitzhak Mandelbaum TEST(StencilToStringTest, RunOp) { 762cf2438ecSYitzhak Mandelbaum auto F1 = [](const MatchResult &R) { return "foo"; }; 763ce2b5cb6SYitzhak Mandelbaum auto S1 = run(F1); 764ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S1->toString(), "run(...)"); 765cf2438ecSYitzhak Mandelbaum } 766cf2438ecSYitzhak Mandelbaum 767ce2b5cb6SYitzhak Mandelbaum TEST(StencilToStringTest, Sequence) { 768d5b98355SYitzhak Mandelbaum auto S = cat("foo", access("x", "m()"), "bar", 76987340a2bSYitzhak Mandelbaum ifBound("x", cat("t"), access("e", "f"))); 770ce2b5cb6SYitzhak Mandelbaum StringRef Expected = R"repr(seq("foo", access("x", "m()"), "bar", )repr" 771ce2b5cb6SYitzhak Mandelbaum R"repr(ifBound("x", "t", access("e", "f"))))repr"; 772ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 773ce2b5cb6SYitzhak Mandelbaum } 774ce2b5cb6SYitzhak Mandelbaum 775ce2b5cb6SYitzhak Mandelbaum TEST(StencilToStringTest, SequenceEmpty) { 776ce2b5cb6SYitzhak Mandelbaum auto S = cat(); 777ce2b5cb6SYitzhak Mandelbaum StringRef Expected = "seq()"; 778ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 779ce2b5cb6SYitzhak Mandelbaum } 780ce2b5cb6SYitzhak Mandelbaum 781ce2b5cb6SYitzhak Mandelbaum TEST(StencilToStringTest, SequenceSingle) { 782ce2b5cb6SYitzhak Mandelbaum auto S = cat("foo"); 783ce2b5cb6SYitzhak Mandelbaum StringRef Expected = "\"foo\""; 784ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 785ce2b5cb6SYitzhak Mandelbaum } 786ce2b5cb6SYitzhak Mandelbaum 787ce2b5cb6SYitzhak Mandelbaum TEST(StencilToStringTest, SequenceFromVector) { 78887340a2bSYitzhak Mandelbaum auto S = catVector({cat("foo"), access("x", "m()"), cat("bar"), 78987340a2bSYitzhak Mandelbaum ifBound("x", cat("t"), access("e", "f"))}); 790ce2b5cb6SYitzhak Mandelbaum StringRef Expected = R"repr(seq("foo", access("x", "m()"), "bar", )repr" 791ce2b5cb6SYitzhak Mandelbaum R"repr(ifBound("x", "t", access("e", "f"))))repr"; 792ce2b5cb6SYitzhak Mandelbaum EXPECT_EQ(S->toString(), Expected); 793d5b98355SYitzhak Mandelbaum } 794e955f8baSYitzhak Mandelbaum } // namespace 795