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
11using namespace clang;
12
13namespace {
14
15struct CastExprVisitor : TestVisitor<CastExprVisitor> {
16 std::function<void(ExplicitCastExpr *)> OnExplicitCast;
17 std::function<void(CastExpr *)> OnCast;
18
19 bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) {
20 if (OnExplicitCast)
21 OnExplicitCast(Expr);
22 return true;
23 }
24
25 bool VisitCastExpr(CastExpr *Expr) {
26 if (OnCast)
27 OnCast(Expr);
28 return true;
29 }
30};
31
32TEST(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(Code: "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
52TEST(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(Code: "struct S { consteval S(int) {} };\n"
60 "S f() { return S(0); }\n",
61 L: 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"
73TEST(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(Code: "struct X { consteval X(const char *) {} };\n"
83 "void f() { X x = \"foobar\"; }\n",
84 L: 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'
96TEST(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(Code: "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 L: CastExprVisitor::Lang_CXX2a);
115}
116
117} // namespace
118

source code of clang/unittests/Tooling/CastExprTest.cpp