//===- unittest/Tooling/CastExprTest.cpp ----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "TestVisitor.h" using namespace clang; namespace { struct CastExprVisitor : TestVisitor { std::function OnExplicitCast; std::function OnCast; bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) override { if (OnExplicitCast) OnExplicitCast(Expr); return true; } bool VisitCastExpr(CastExpr *Expr) override { if (OnCast) OnCast(Expr); return true; } }; TEST(CastExprTest, GetSubExprAsWrittenThroughMaterializedTemporary) { CastExprVisitor Visitor; Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) { auto Sub = Expr->getSubExprAsWritten(); EXPECT_TRUE(isa(Sub)) << "Expected DeclRefExpr, but saw " << Sub->getStmtClassName(); }; Visitor.runOver("struct S1 {};\n" "struct S2 { operator S1(); };\n" "S1 f(S2 s) { return static_cast(s); }\n"); } // Verify that getSubExprAsWritten looks through a ConstantExpr in a scenario // like // // CXXFunctionalCastExpr functional cast to struct S // `-ConstantExpr 'S' // |-value: Struct // `-CXXConstructExpr 'S' 'void (int)' // `-IntegerLiteral 'int' 0 TEST(CastExprTest, GetSubExprAsWrittenThroughConstantExpr) { CastExprVisitor Visitor; Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) { auto *Sub = Expr->getSubExprAsWritten(); EXPECT_TRUE(isa(Sub)) << "Expected IntegerLiteral, but saw " << Sub->getStmtClassName(); }; Visitor.runOver("struct S { consteval S(int) {} };\n" "S f() { return S(0); }\n", CastExprVisitor::Lang_CXX2a); } // Verify that getConversionFunction looks through a ConstantExpr for implicit // constructor conversions (https://github.com/llvm/llvm-project/issues/53044): // // `-ImplicitCastExpr 'X' // `-ConstantExpr 'X' // |-value: Struct // `-CXXConstructExpr 'X' 'void (const char *)' // `-ImplicitCastExpr 'const char *' // `-StringLiteral 'const char [7]' lvalue "foobar" TEST(CastExprTest, GetCtorConversionFunctionThroughConstantExpr) { CastExprVisitor Visitor; Visitor.OnCast = [](CastExpr *Expr) { if (Expr->getCastKind() == CK_ConstructorConversion) { auto *Conv = Expr->getConversionFunction(); EXPECT_TRUE(isa(Conv)) << "Expected CXXConstructorDecl, but saw " << Conv->getDeclKindName(); } }; Visitor.runOver("struct X { consteval X(const char *) {} };\n" "void f() { X x = \"foobar\"; }\n", CastExprVisitor::Lang_CXX2a); } // Verify that getConversionFunction looks through a ConstantExpr for implicit // user-defined conversions. // // `-ImplicitCastExpr 'const char *' // `-ConstantExpr 'const char *' // |-value: LValue // `-CXXMemberCallExpr 'const char *' // `-MemberExpr '' .operator const char * // `-DeclRefExpr 'const X' lvalue Var 'x' 'const X' TEST(CastExprTest, GetUserDefinedConversionFunctionThroughConstantExpr) { CastExprVisitor Visitor; Visitor.OnCast = [](CastExpr *Expr) { if (Expr->getCastKind() == CK_UserDefinedConversion) { auto *Conv = Expr->getConversionFunction(); EXPECT_TRUE(isa(Conv)) << "Expected CXXMethodDecl, but saw " << Conv->getDeclKindName(); } }; Visitor.runOver("struct X {\n" " consteval operator const char *() const {\n" " return nullptr;\n" " }\n" "};\n" "const char *f() {\n" " constexpr X x;\n" " return x;\n" "}\n", CastExprVisitor::Lang_CXX2a); } } // namespace