xref: /llvm-project/clang/unittests/AST/ASTExprTest.cpp (revision 3c42e10afdc518f6d8be5620289ef0da0bf03c5f)
1 //===- unittests/AST/ASTExprTest.cpp --- AST Expr tests -------------------===//
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 // This file contains tests for AST Expr related methods.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "ASTPrint.h"
14 #include "clang/AST/ASTContext.h"
15 #include "clang/AST/Expr.h"
16 #include "clang/AST/IgnoreExpr.h"
17 #include "clang/ASTMatchers/ASTMatchFinder.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "gtest/gtest.h"
20 
21 using namespace clang;
22 
23 using clang::ast_matchers::cxxRecordDecl;
24 using clang::ast_matchers::hasName;
25 using clang::ast_matchers::match;
26 using clang::ast_matchers::varDecl;
27 using clang::tooling::buildASTFromCode;
28 
createIntLiteral(ASTContext & Ctx,uint32_t Value)29 static IntegerLiteral *createIntLiteral(ASTContext &Ctx, uint32_t Value) {
30   const int numBits = 32;
31   return IntegerLiteral::Create(Ctx, llvm::APInt(numBits, Value), Ctx.IntTy,
32                                 {});
33 }
34 
getCXXRecordDeclNode(ASTUnit * AST,const std::string & Name)35 const CXXRecordDecl *getCXXRecordDeclNode(ASTUnit *AST,
36                                           const std::string &Name) {
37   auto Result =
38       match(cxxRecordDecl(hasName(Name)).bind("record"), AST->getASTContext());
39   EXPECT_FALSE(Result.empty());
40   return Result[0].getNodeAs<CXXRecordDecl>("record");
41 }
42 
getVariableNode(ASTUnit * AST,const std::string & Name)43 const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
44   auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
45   EXPECT_EQ(Result.size(), 1u);
46   return Result[0].getNodeAs<VarDecl>("var");
47 }
48 
TEST(ASTExpr,IgnoreExprCallbackForwarded)49 TEST(ASTExpr, IgnoreExprCallbackForwarded) {
50   constexpr char Code[] = "";
51   auto AST = tooling::buildASTFromCodeWithArgs(Code, /*Args=*/{"-std=c++20"});
52   ASTContext &Ctx = AST->getASTContext();
53 
54   struct IgnoreParens {
55     Expr *operator()(Expr *E) & { return nullptr; }
56     Expr *operator()(Expr *E) && {
57       if (auto *PE = dyn_cast<ParenExpr>(E)) {
58         return PE->getSubExpr();
59       }
60       return E;
61     }
62   };
63 
64   {
65     auto *IntExpr = createIntLiteral(Ctx, 10);
66     ParenExpr *PE =
67         new (Ctx) ParenExpr(SourceLocation{}, SourceLocation{}, IntExpr);
68     EXPECT_EQ(IntExpr, IgnoreExprNodes(PE, IgnoreParens{}));
69   }
70 
71   {
72     IgnoreParens CB{};
73     auto *IntExpr = createIntLiteral(Ctx, 10);
74     ParenExpr *PE =
75         new (Ctx) ParenExpr(SourceLocation{}, SourceLocation{}, IntExpr);
76     EXPECT_EQ(nullptr, IgnoreExprNodes(PE, CB));
77   }
78 }
79 
TEST(ASTExpr,InitListIsConstantInitialized)80 TEST(ASTExpr, InitListIsConstantInitialized) {
81   auto AST = buildASTFromCode(R"cpp(
82     struct Empty {};
83     struct Foo : Empty { int x, y; };
84     int gv;
85   )cpp");
86   ASTContext &Ctx = AST->getASTContext();
87   const CXXRecordDecl *Empty = getCXXRecordDeclNode(AST.get(), "Empty");
88   const CXXRecordDecl *Foo = getCXXRecordDeclNode(AST.get(), "Foo");
89 
90   SourceLocation Loc{};
91   InitListExpr *BaseInit = new (Ctx) InitListExpr(Ctx, Loc, {}, Loc);
92   BaseInit->setType(Ctx.getRecordType(Empty));
93   Expr *Exprs[3] = {
94       BaseInit,
95       createIntLiteral(Ctx, 13),
96       createIntLiteral(Ctx, 42),
97   };
98   InitListExpr *FooInit = new (Ctx) InitListExpr(Ctx, Loc, Exprs, Loc);
99   FooInit->setType(Ctx.getRecordType(Foo));
100   EXPECT_TRUE(FooInit->isConstantInitializer(Ctx, false));
101 
102   // Replace the last initializer with something non-constant and make sure
103   // this returns false. Previously we had a bug where we didn't count base
104   // initializers, and only iterated over fields.
105   const VarDecl *GV = getVariableNode(AST.get(), "gv");
106   auto *Ref = new (Ctx) DeclRefExpr(Ctx, const_cast<VarDecl *>(GV), false,
107                                     Ctx.IntTy, VK_LValue, Loc);
108   (void)FooInit->updateInit(Ctx, 2, Ref);
109   EXPECT_FALSE(FooInit->isConstantInitializer(Ctx, false));
110 }
111