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