1f31b0dc4SStephan Bergmann //===- unittest/Tooling/CastExprTest.cpp ----------------------------------===// 2f31b0dc4SStephan Bergmann // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f31b0dc4SStephan Bergmann // 7f31b0dc4SStephan Bergmann //===----------------------------------------------------------------------===// 8f31b0dc4SStephan Bergmann 9f31b0dc4SStephan Bergmann #include "TestVisitor.h" 10f31b0dc4SStephan Bergmann 11f31b0dc4SStephan Bergmann using namespace clang; 12f31b0dc4SStephan Bergmann 13f31b0dc4SStephan Bergmann namespace { 14f31b0dc4SStephan Bergmann 15*4e600751SSirraide struct CastExprVisitor : TestVisitor { 16f31b0dc4SStephan Bergmann std::function<void(ExplicitCastExpr *)> OnExplicitCast; 17403d7d8dSAaron Ballman std::function<void(CastExpr *)> OnCast; 18f31b0dc4SStephan Bergmann 19*4e600751SSirraide bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) override { 20f31b0dc4SStephan Bergmann if (OnExplicitCast) 21f31b0dc4SStephan Bergmann OnExplicitCast(Expr); 22f31b0dc4SStephan Bergmann return true; 23f31b0dc4SStephan Bergmann } 24403d7d8dSAaron Ballman 25*4e600751SSirraide bool VisitCastExpr(CastExpr *Expr) override { 26403d7d8dSAaron Ballman if (OnCast) 27403d7d8dSAaron Ballman OnCast(Expr); 28403d7d8dSAaron Ballman return true; 29403d7d8dSAaron Ballman } 30f31b0dc4SStephan Bergmann }; 31f31b0dc4SStephan Bergmann 32f31b0dc4SStephan Bergmann TEST(CastExprTest, GetSubExprAsWrittenThroughMaterializedTemporary) { 33f31b0dc4SStephan Bergmann CastExprVisitor Visitor; 34f31b0dc4SStephan Bergmann Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) { 35f31b0dc4SStephan Bergmann auto Sub = Expr->getSubExprAsWritten(); 36f31b0dc4SStephan Bergmann EXPECT_TRUE(isa<DeclRefExpr>(Sub)) 37f31b0dc4SStephan Bergmann << "Expected DeclRefExpr, but saw " << Sub->getStmtClassName(); 38f31b0dc4SStephan Bergmann }; 39f31b0dc4SStephan Bergmann Visitor.runOver("struct S1 {};\n" 40f31b0dc4SStephan Bergmann "struct S2 { operator S1(); };\n" 41f31b0dc4SStephan Bergmann "S1 f(S2 s) { return static_cast<S1>(s); }\n"); 42f31b0dc4SStephan Bergmann } 43f31b0dc4SStephan Bergmann 44215ed9b3SStephan Bergmann // Verify that getSubExprAsWritten looks through a ConstantExpr in a scenario 45215ed9b3SStephan Bergmann // like 46215ed9b3SStephan Bergmann // 47215ed9b3SStephan Bergmann // CXXFunctionalCastExpr functional cast to struct S <ConstructorConversion> 48215ed9b3SStephan Bergmann // `-ConstantExpr 'S' 49215ed9b3SStephan Bergmann // |-value: Struct 50215ed9b3SStephan Bergmann // `-CXXConstructExpr 'S' 'void (int)' 51215ed9b3SStephan Bergmann // `-IntegerLiteral 'int' 0 52215ed9b3SStephan Bergmann TEST(CastExprTest, GetSubExprAsWrittenThroughConstantExpr) { 53215ed9b3SStephan Bergmann CastExprVisitor Visitor; 54215ed9b3SStephan Bergmann Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) { 55215ed9b3SStephan Bergmann auto *Sub = Expr->getSubExprAsWritten(); 56215ed9b3SStephan Bergmann EXPECT_TRUE(isa<IntegerLiteral>(Sub)) 57215ed9b3SStephan Bergmann << "Expected IntegerLiteral, but saw " << Sub->getStmtClassName(); 58215ed9b3SStephan Bergmann }; 59215ed9b3SStephan Bergmann Visitor.runOver("struct S { consteval S(int) {} };\n" 60215ed9b3SStephan Bergmann "S f() { return S(0); }\n", 61215ed9b3SStephan Bergmann CastExprVisitor::Lang_CXX2a); 62215ed9b3SStephan Bergmann } 63215ed9b3SStephan Bergmann 64403d7d8dSAaron Ballman // Verify that getConversionFunction looks through a ConstantExpr for implicit 65403d7d8dSAaron Ballman // constructor conversions (https://github.com/llvm/llvm-project/issues/53044): 66403d7d8dSAaron Ballman // 67403d7d8dSAaron Ballman // `-ImplicitCastExpr 'X' <ConstructorConversion> 68403d7d8dSAaron Ballman // `-ConstantExpr 'X' 69403d7d8dSAaron Ballman // |-value: Struct 70403d7d8dSAaron Ballman // `-CXXConstructExpr 'X' 'void (const char *)' 71403d7d8dSAaron Ballman // `-ImplicitCastExpr 'const char *' <ArrayToPointerDecay> 72403d7d8dSAaron Ballman // `-StringLiteral 'const char [7]' lvalue "foobar" 73403d7d8dSAaron Ballman TEST(CastExprTest, GetCtorConversionFunctionThroughConstantExpr) { 74403d7d8dSAaron Ballman CastExprVisitor Visitor; 75403d7d8dSAaron Ballman Visitor.OnCast = [](CastExpr *Expr) { 76403d7d8dSAaron Ballman if (Expr->getCastKind() == CK_ConstructorConversion) { 77403d7d8dSAaron Ballman auto *Conv = Expr->getConversionFunction(); 78403d7d8dSAaron Ballman EXPECT_TRUE(isa<CXXConstructorDecl>(Conv)) 79403d7d8dSAaron Ballman << "Expected CXXConstructorDecl, but saw " << Conv->getDeclKindName(); 80403d7d8dSAaron Ballman } 81403d7d8dSAaron Ballman }; 82403d7d8dSAaron Ballman Visitor.runOver("struct X { consteval X(const char *) {} };\n" 83403d7d8dSAaron Ballman "void f() { X x = \"foobar\"; }\n", 84403d7d8dSAaron Ballman CastExprVisitor::Lang_CXX2a); 85403d7d8dSAaron Ballman } 86403d7d8dSAaron Ballman 87403d7d8dSAaron Ballman // Verify that getConversionFunction looks through a ConstantExpr for implicit 88403d7d8dSAaron Ballman // user-defined conversions. 89403d7d8dSAaron Ballman // 90403d7d8dSAaron Ballman // `-ImplicitCastExpr 'const char *' <UserDefinedConversion> 91403d7d8dSAaron Ballman // `-ConstantExpr 'const char *' 92403d7d8dSAaron Ballman // |-value: LValue 93403d7d8dSAaron Ballman // `-CXXMemberCallExpr 'const char *' 94403d7d8dSAaron Ballman // `-MemberExpr '<bound member function type>' .operator const char * 95403d7d8dSAaron Ballman // `-DeclRefExpr 'const X' lvalue Var 'x' 'const X' 96403d7d8dSAaron Ballman TEST(CastExprTest, GetUserDefinedConversionFunctionThroughConstantExpr) { 97403d7d8dSAaron Ballman CastExprVisitor Visitor; 98403d7d8dSAaron Ballman Visitor.OnCast = [](CastExpr *Expr) { 99403d7d8dSAaron Ballman if (Expr->getCastKind() == CK_UserDefinedConversion) { 100403d7d8dSAaron Ballman auto *Conv = Expr->getConversionFunction(); 101403d7d8dSAaron Ballman EXPECT_TRUE(isa<CXXMethodDecl>(Conv)) 102403d7d8dSAaron Ballman << "Expected CXXMethodDecl, but saw " << Conv->getDeclKindName(); 103403d7d8dSAaron Ballman } 104403d7d8dSAaron Ballman }; 105403d7d8dSAaron Ballman Visitor.runOver("struct X {\n" 106403d7d8dSAaron Ballman " consteval operator const char *() const {\n" 107403d7d8dSAaron Ballman " return nullptr;\n" 108403d7d8dSAaron Ballman " }\n" 109403d7d8dSAaron Ballman "};\n" 110403d7d8dSAaron Ballman "const char *f() {\n" 111403d7d8dSAaron Ballman " constexpr X x;\n" 112403d7d8dSAaron Ballman " return x;\n" 113403d7d8dSAaron Ballman "}\n", 114403d7d8dSAaron Ballman CastExprVisitor::Lang_CXX2a); 115403d7d8dSAaron Ballman } 116403d7d8dSAaron Ballman 117d7ddad40SKim Gräsman } // namespace 118