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