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