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