xref: /llvm-project/clang/unittests/Tooling/CastExprTest.cpp (revision 4e600751d2f7e8e7b85a71b7128b68444bdde91b)
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