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<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 | |
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(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 |
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(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" |
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(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' |
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(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 | |