xref: /llvm-project/clang/unittests/Tooling/StencilTest.cpp (revision 512cecad4c384c84b79fea050a755cb7e46c6ac5)
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