| 1 | //===- unittest/Tooling/CastExprTest.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 "TestVisitor.h" |
| 10 | |
| 11 | using namespace clang; |
| 12 | |
| 13 | namespace { |
| 14 | |
| 15 | struct CastExprVisitor : TestVisitor { |
| 16 | std::function<void(ExplicitCastExpr *)> OnExplicitCast; |
| 17 | std::function<void(CastExpr *)> OnCast; |
| 18 | |
| 19 | bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) override { |
| 20 | if (OnExplicitCast) |
| 21 | OnExplicitCast(Expr); |
| 22 | return true; |
| 23 | } |
| 24 | |
| 25 | bool VisitCastExpr(CastExpr *Expr) override { |
| 26 | if (OnCast) |
| 27 | OnCast(Expr); |
| 28 | return true; |
| 29 | } |
| 30 | }; |
| 31 | |
| 32 | TEST(CastExprTest, GetSubExprAsWrittenThroughMaterializedTemporary) { |
| 33 | CastExprVisitor Visitor; |
| 34 | Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) { |
| 35 | auto Sub = Expr->getSubExprAsWritten(); |
| 36 | EXPECT_TRUE(isa<DeclRefExpr>(Sub)) |
| 37 | << "Expected DeclRefExpr, but saw " << Sub->getStmtClassName(); |
| 38 | }; |
| 39 | Visitor.runOver("struct S1 {};\n" |
| 40 | "struct S2 { operator S1(); };\n" |
| 41 | "S1 f(S2 s) { return static_cast<S1>(s); }\n" ); |
| 42 | } |
| 43 | |
| 44 | // Verify that getSubExprAsWritten looks through a ConstantExpr in a scenario |
| 45 | // like |
| 46 | // |
| 47 | // CXXFunctionalCastExpr functional cast to struct S <ConstructorConversion> |
| 48 | // `-ConstantExpr 'S' |
| 49 | // |-value: Struct |
| 50 | // `-CXXConstructExpr 'S' 'void (int)' |
| 51 | // `-IntegerLiteral 'int' 0 |
| 52 | TEST(CastExprTest, GetSubExprAsWrittenThroughConstantExpr) { |
| 53 | CastExprVisitor Visitor; |
| 54 | Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) { |
| 55 | auto *Sub = Expr->getSubExprAsWritten(); |
| 56 | EXPECT_TRUE(isa<IntegerLiteral>(Sub)) |
| 57 | << "Expected IntegerLiteral, but saw " << Sub->getStmtClassName(); |
| 58 | }; |
| 59 | Visitor.runOver("struct S { consteval S(int) {} };\n" |
| 60 | "S f() { return S(0); }\n" , |
| 61 | CastExprVisitor::Lang_CXX2a); |
| 62 | } |
| 63 | |
| 64 | // Verify that getConversionFunction looks through a ConstantExpr for implicit |
| 65 | // constructor conversions (https://github.com/llvm/llvm-project/issues/53044): |
| 66 | // |
| 67 | // `-ImplicitCastExpr 'X' <ConstructorConversion> |
| 68 | // `-ConstantExpr 'X' |
| 69 | // |-value: Struct |
| 70 | // `-CXXConstructExpr 'X' 'void (const char *)' |
| 71 | // `-ImplicitCastExpr 'const char *' <ArrayToPointerDecay> |
| 72 | // `-StringLiteral 'const char [7]' lvalue "foobar" |
| 73 | TEST(CastExprTest, GetCtorConversionFunctionThroughConstantExpr) { |
| 74 | CastExprVisitor Visitor; |
| 75 | Visitor.OnCast = [](CastExpr *Expr) { |
| 76 | if (Expr->getCastKind() == CK_ConstructorConversion) { |
| 77 | auto *Conv = Expr->getConversionFunction(); |
| 78 | EXPECT_TRUE(isa<CXXConstructorDecl>(Conv)) |
| 79 | << "Expected CXXConstructorDecl, but saw " << Conv->getDeclKindName(); |
| 80 | } |
| 81 | }; |
| 82 | Visitor.runOver("struct X { consteval X(const char *) {} };\n" |
| 83 | "void f() { X x = \"foobar\"; }\n" , |
| 84 | CastExprVisitor::Lang_CXX2a); |
| 85 | } |
| 86 | |
| 87 | // Verify that getConversionFunction looks through a ConstantExpr for implicit |
| 88 | // user-defined conversions. |
| 89 | // |
| 90 | // `-ImplicitCastExpr 'const char *' <UserDefinedConversion> |
| 91 | // `-ConstantExpr 'const char *' |
| 92 | // |-value: LValue |
| 93 | // `-CXXMemberCallExpr 'const char *' |
| 94 | // `-MemberExpr '<bound member function type>' .operator const char * |
| 95 | // `-DeclRefExpr 'const X' lvalue Var 'x' 'const X' |
| 96 | TEST(CastExprTest, GetUserDefinedConversionFunctionThroughConstantExpr) { |
| 97 | CastExprVisitor Visitor; |
| 98 | Visitor.OnCast = [](CastExpr *Expr) { |
| 99 | if (Expr->getCastKind() == CK_UserDefinedConversion) { |
| 100 | auto *Conv = Expr->getConversionFunction(); |
| 101 | EXPECT_TRUE(isa<CXXMethodDecl>(Conv)) |
| 102 | << "Expected CXXMethodDecl, but saw " << Conv->getDeclKindName(); |
| 103 | } |
| 104 | }; |
| 105 | Visitor.runOver("struct X {\n" |
| 106 | " consteval operator const char *() const {\n" |
| 107 | " return nullptr;\n" |
| 108 | " }\n" |
| 109 | "};\n" |
| 110 | "const char *f() {\n" |
| 111 | " constexpr X x;\n" |
| 112 | " return x;\n" |
| 113 | "}\n" , |
| 114 | CastExprVisitor::Lang_CXX2a); |
| 115 | } |
| 116 | |
| 117 | } // namespace |
| 118 | |