[TableGen] Fix validateOperandClass for non Phyical Reg (#118146)
[llvm-project.git] / clang / unittests / Tooling / StencilTest.cpp
blob445912a53e8b62643a9b7b2d9e5fa355279f0b44
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 //===----------------------------------------------------------------------===//
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>
21 using namespace clang;
22 using namespace transformer;
23 using namespace ast_matchers;
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;
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;
47 template<class T> T desugar() { return T(); };
48 )cc";
49 return (Preface + ExtraPreface + "auto stencil_test_snippet = []{" +
50 StatementCode + "};")
51 .str();
54 static DeclarationMatcher wrapMatcher(const StatementMatcher &Matcher) {
55 return varDecl(hasName("stencil_test_snippet"),
56 hasDescendant(compoundStmt(hasAnySubstatement(Matcher))));
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;
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;
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;
89 return TestMatch{std::move(AstUnit), MatchResult(Matches[0], &Context)};
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) {}
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);
125 if (Err) {
126 ADD_FAILURE() << "Unhandled error: " << llvm::toString(std::move(Err));
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")));
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;"));
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;
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)));
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)));
194 TEST_F(StencilTest, SelectionOp) {
195 StringRef Id = "id";
196 testExpr(Id, "3;", cat(node(std::string(Id))), "3");
199 TEST_F(StencilTest, IfBoundOpBound) {
200 StringRef Id = "id";
201 testExpr(Id, "3;", ifBound(Id, cat("5"), cat("7")), "5");
204 TEST_F(StencilTest, IfBoundOpUnbound) {
205 StringRef Id = "id";
206 testExpr(Id, "3;", ifBound("other", cat("5"), cat("7")), "7");
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()));
216 static auto selectStencil() {
217 return selectBound({
218 {"int", cat("I")},
219 {"bool", cat("B")},
220 {"bool", cat("redundant")},
221 {"float", cat("F")},
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")));
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")));
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")))));
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")));
261 TEST_F(StencilTest, ExpressionOpNoParens) {
262 StringRef Id = "id";
263 testExpr(Id, "3;", expression(Id), "3");
266 // Don't parenthesize a parens expression.
267 TEST_F(StencilTest, ExpressionOpNoParensParens) {
268 StringRef Id = "id";
269 testExpr(Id, "(3);", expression(Id), "(3)");
272 TEST_F(StencilTest, ExpressionOpBinaryOpParens) {
273 StringRef Id = "id";
274 testExpr(Id, "3+4;", expression(Id), "(3+4)");
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")));
286 TEST_F(StencilTest, DerefPointer) {
287 StringRef Id = "id";
288 testExpr(Id, "int *x; x;", deref(Id), "*x");
291 TEST_F(StencilTest, DerefBinOp) {
292 StringRef Id = "id";
293 testExpr(Id, "int *x; x + 1;", deref(Id), "*(x + 1)");
296 TEST_F(StencilTest, DerefAddressExpr) {
297 StringRef Id = "id";
298 testExpr(Id, "int x; &x;", deref(Id), "x");
301 TEST_F(StencilTest, AddressOfValue) {
302 StringRef Id = "id";
303 testExpr(Id, "int x; x;", addressOf(Id), "&x");
306 TEST_F(StencilTest, AddressOfDerefExpr) {
307 StringRef Id = "id";
308 testExpr(Id, "int *x; *x;", addressOf(Id), "x");
311 TEST_F(StencilTest, MaybeDerefValue) {
312 StringRef Id = "id";
313 testExpr(Id, "int x; x;", maybeDeref(Id), "x");
316 TEST_F(StencilTest, MaybeDerefPointer) {
317 StringRef Id = "id";
318 testExpr(Id, "int *x; x;", maybeDeref(Id), "*x");
321 TEST_F(StencilTest, MaybeDerefBinOp) {
322 StringRef Id = "id";
323 testExpr(Id, "int *x; x + 1;", maybeDeref(Id), "*(x + 1)");
326 TEST_F(StencilTest, MaybeDerefAddressExpr) {
327 StringRef Id = "id";
328 testExpr(Id, "int x; &x;", maybeDeref(Id), "x");
331 TEST_F(StencilTest, MaybeDerefSmartPointer) {
332 StringRef Id = "id";
333 std::string Snippet = R"cc(
334 std::unique_ptr<S> x;
336 )cc";
337 testExpr(Id, Snippet, maybeDeref(Id), "*x");
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"));
350 TEST_F(StencilTest, MaybeAddressOfPointer) {
351 StringRef Id = "id";
352 testExpr(Id, "int *x; x;", maybeAddressOf(Id), "x");
355 TEST_F(StencilTest, MaybeAddressOfValue) {
356 StringRef Id = "id";
357 testExpr(Id, "int x; x;", addressOf(Id), "&x");
360 TEST_F(StencilTest, MaybeAddressOfBinOp) {
361 StringRef Id = "id";
362 testExpr(Id, "int x; x + 1;", maybeAddressOf(Id), "&(x + 1)");
365 TEST_F(StencilTest, MaybeAddressOfDerefExpr) {
366 StringRef Id = "id";
367 testExpr(Id, "int *x; *x;", addressOf(Id), "x");
370 TEST_F(StencilTest, MaybeAddressOfSmartPointer) {
371 StringRef Id = "id";
372 testExpr(Id, "std::unique_ptr<S> x; x;", maybeAddressOf(Id), "x");
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"));
385 TEST_F(StencilTest, MaybeAddressOfSmartPointerDerefNoCancel) {
386 StringRef Id = "id";
387 testExpr(Id, "std::unique_ptr<S> x; *x;", maybeAddressOf(Id), "&*x");
390 TEST_F(StencilTest, AccessOpValue) {
391 StringRef Snippet = R"cc(
392 S x;
394 )cc";
395 StringRef Id = "id";
396 testExpr(Id, Snippet, access(Id, "field"), "x.field");
399 TEST_F(StencilTest, AccessOpValueExplicitText) {
400 StringRef Snippet = R"cc(
401 S x;
403 )cc";
404 StringRef Id = "id";
405 testExpr(Id, Snippet, access(Id, cat("field")), "x.field");
408 TEST_F(StencilTest, AccessOpValueAddress) {
409 StringRef Snippet = R"cc(
410 S x;
412 )cc";
413 StringRef Id = "id";
414 testExpr(Id, Snippet, access(Id, "field"), "x.field");
417 TEST_F(StencilTest, AccessOpPointer) {
418 StringRef Snippet = R"cc(
419 S *x;
421 )cc";
422 StringRef Id = "id";
423 testExpr(Id, Snippet, access(Id, "field"), "x->field");
426 TEST_F(StencilTest, AccessOpPointerDereference) {
427 StringRef Snippet = R"cc(
428 S *x;
430 )cc";
431 StringRef Id = "id";
432 testExpr(Id, Snippet, access(Id, "field"), "x->field");
435 TEST_F(StencilTest, AccessOpSmartPointer) {
436 StringRef Snippet = R"cc(
437 std::unique_ptr<S> x;
439 )cc";
440 StringRef Id = "id";
441 testExpr(Id, Snippet, access(Id, "field"), "x->field");
444 TEST_F(StencilTest, AccessOpSmartPointerDereference) {
445 StringRef Snippet = R"cc(
446 std::unique_ptr<S> x;
448 )cc";
449 StringRef Id = "id";
450 testExpr(Id, Snippet, access(Id, "field"), "x->field");
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"));
466 TEST_F(StencilTest, AccessOpExplicitThis) {
467 using clang::ast_matchers::hasObjectExpression;
468 using clang::ast_matchers::memberExpr;
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; }
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"));
488 TEST_F(StencilTest, AccessOpImplicitThis) {
489 using clang::ast_matchers::hasObjectExpression;
490 using clang::ast_matchers::memberExpr;
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; }
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"));
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)));
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)));
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)));
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)));
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)));
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)));
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)));
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)));
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");
596 testExpr(Id, "3;", run(SimpleFn), "Bound");
599 TEST_F(StencilTest, CatOfMacroRangeSucceeds) {
600 StringRef Snippet = R"cpp(
601 #define MACRO 3.77
602 double foo(double d);
603 foo(MACRO);)cpp";
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"));
614 TEST_F(StencilTest, CatOfMacroArgRangeSucceeds) {
615 StringRef Snippet = R"cpp(
616 #define MACRO(a, b) a + b
617 MACRO(2, 3);)cpp";
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"));
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";
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"));
641 TEST_F(StencilTest, CatOfInvalidRangeFails) {
642 StringRef Snippet = R"cpp(
643 #define MACRO (3.77)
644 double foo(double d);
645 foo(MACRO);)cpp";
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")));
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`).
667 TEST(StencilToStringTest, RawTextOp) {
668 auto S = cat("foo bar baz");
669 StringRef Expected = R"("foo bar baz")";
670 EXPECT_EQ(S->toString(), Expected);
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);
679 TEST(StencilToStringTest, DescribeOp) {
680 auto S = describe("Id");
681 StringRef Expected = R"repr(describe("Id"))repr";
682 EXPECT_EQ(S->toString(), Expected);
685 TEST(StencilToStringTest, DebugPrintNodeOp) {
686 auto S = dPrint("Id");
687 StringRef Expected = R"repr(dPrint("Id"))repr";
688 EXPECT_EQ(S->toString(), Expected);
691 TEST(StencilToStringTest, ExpressionOp) {
692 auto S = expression("Id");
693 StringRef Expected = R"repr(expression("Id"))repr";
694 EXPECT_EQ(S->toString(), Expected);
697 TEST(StencilToStringTest, DerefOp) {
698 auto S = deref("Id");
699 StringRef Expected = R"repr(deref("Id"))repr";
700 EXPECT_EQ(S->toString(), Expected);
703 TEST(StencilToStringTest, AddressOfOp) {
704 auto S = addressOf("Id");
705 StringRef Expected = R"repr(addressOf("Id"))repr";
706 EXPECT_EQ(S->toString(), Expected);
709 TEST(StencilToStringTest, SelectionOp) {
710 auto S1 = cat(node("node1"));
711 EXPECT_EQ(S1->toString(), "selection(...)");
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);
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);
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);
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);
739 TEST(StencilToStringTest, SelectBoundOp) {
740 auto S = selectBound({
741 {"int", cat("I")},
742 {"float", cat("F")},
744 StringRef Expected = R"repr(selectBound({{"int", "I"}, {"float", "F"}}))repr";
745 EXPECT_EQ(S->toString(), Expected);
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);
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);
761 TEST(StencilToStringTest, RunOp) {
762 auto F1 = [](const MatchResult &R) { return "foo"; };
763 auto S1 = run(F1);
764 EXPECT_EQ(S1->toString(), "run(...)");
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);
775 TEST(StencilToStringTest, SequenceEmpty) {
776 auto S = cat();
777 StringRef Expected = "seq()";
778 EXPECT_EQ(S->toString(), Expected);
781 TEST(StencilToStringTest, SequenceSingle) {
782 auto S = cat("foo");
783 StringRef Expected = "\"foo\"";
784 EXPECT_EQ(S->toString(), Expected);
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);
794 } // namespace