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