xref: /llvm-project/clang/unittests/AST/ASTExprTest.cpp (revision 3c42e10afdc518f6d8be5620289ef0da0bf03c5f)
158ec6e09SChris Cotter //===- unittests/AST/ASTExprTest.cpp --- AST Expr tests -------------------===//
258ec6e09SChris Cotter //
358ec6e09SChris Cotter // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
458ec6e09SChris Cotter // See https://llvm.org/LICENSE.txt for license information.
558ec6e09SChris Cotter // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
658ec6e09SChris Cotter //
758ec6e09SChris Cotter //===----------------------------------------------------------------------===//
858ec6e09SChris Cotter //
958ec6e09SChris Cotter // This file contains tests for AST Expr related methods.
1058ec6e09SChris Cotter //
1158ec6e09SChris Cotter //===----------------------------------------------------------------------===//
1258ec6e09SChris Cotter 
1358ec6e09SChris Cotter #include "ASTPrint.h"
1458ec6e09SChris Cotter #include "clang/AST/ASTContext.h"
1558ec6e09SChris Cotter #include "clang/AST/Expr.h"
1658ec6e09SChris Cotter #include "clang/AST/IgnoreExpr.h"
1758ec6e09SChris Cotter #include "clang/ASTMatchers/ASTMatchFinder.h"
1858ec6e09SChris Cotter #include "clang/Tooling/Tooling.h"
1958ec6e09SChris Cotter #include "gtest/gtest.h"
2058ec6e09SChris Cotter 
2158ec6e09SChris Cotter using namespace clang;
2258ec6e09SChris Cotter 
23*3c42e10aSReid Kleckner using clang::ast_matchers::cxxRecordDecl;
24*3c42e10aSReid Kleckner using clang::ast_matchers::hasName;
25*3c42e10aSReid Kleckner using clang::ast_matchers::match;
26*3c42e10aSReid Kleckner using clang::ast_matchers::varDecl;
27*3c42e10aSReid Kleckner using clang::tooling::buildASTFromCode;
28*3c42e10aSReid Kleckner 
createIntLiteral(ASTContext & Ctx,uint32_t Value)29*3c42e10aSReid Kleckner static IntegerLiteral *createIntLiteral(ASTContext &Ctx, uint32_t Value) {
30*3c42e10aSReid Kleckner   const int numBits = 32;
31*3c42e10aSReid Kleckner   return IntegerLiteral::Create(Ctx, llvm::APInt(numBits, Value), Ctx.IntTy,
32*3c42e10aSReid Kleckner                                 {});
33*3c42e10aSReid Kleckner }
34*3c42e10aSReid Kleckner 
getCXXRecordDeclNode(ASTUnit * AST,const std::string & Name)35*3c42e10aSReid Kleckner const CXXRecordDecl *getCXXRecordDeclNode(ASTUnit *AST,
36*3c42e10aSReid Kleckner                                           const std::string &Name) {
37*3c42e10aSReid Kleckner   auto Result =
38*3c42e10aSReid Kleckner       match(cxxRecordDecl(hasName(Name)).bind("record"), AST->getASTContext());
39*3c42e10aSReid Kleckner   EXPECT_FALSE(Result.empty());
40*3c42e10aSReid Kleckner   return Result[0].getNodeAs<CXXRecordDecl>("record");
41*3c42e10aSReid Kleckner }
42*3c42e10aSReid Kleckner 
getVariableNode(ASTUnit * AST,const std::string & Name)43*3c42e10aSReid Kleckner const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
44*3c42e10aSReid Kleckner   auto Result = match(varDecl(hasName(Name)).bind("var"), AST->getASTContext());
45*3c42e10aSReid Kleckner   EXPECT_EQ(Result.size(), 1u);
46*3c42e10aSReid Kleckner   return Result[0].getNodeAs<VarDecl>("var");
47*3c42e10aSReid Kleckner }
48*3c42e10aSReid Kleckner 
TEST(ASTExpr,IgnoreExprCallbackForwarded)4958ec6e09SChris Cotter TEST(ASTExpr, IgnoreExprCallbackForwarded) {
5058ec6e09SChris Cotter   constexpr char Code[] = "";
5158ec6e09SChris Cotter   auto AST = tooling::buildASTFromCodeWithArgs(Code, /*Args=*/{"-std=c++20"});
5258ec6e09SChris Cotter   ASTContext &Ctx = AST->getASTContext();
5358ec6e09SChris Cotter 
5458ec6e09SChris Cotter   struct IgnoreParens {
5558ec6e09SChris Cotter     Expr *operator()(Expr *E) & { return nullptr; }
5658ec6e09SChris Cotter     Expr *operator()(Expr *E) && {
5758ec6e09SChris Cotter       if (auto *PE = dyn_cast<ParenExpr>(E)) {
5858ec6e09SChris Cotter         return PE->getSubExpr();
5958ec6e09SChris Cotter       }
6058ec6e09SChris Cotter       return E;
6158ec6e09SChris Cotter     }
6258ec6e09SChris Cotter   };
6358ec6e09SChris Cotter 
6458ec6e09SChris Cotter   {
65*3c42e10aSReid Kleckner     auto *IntExpr = createIntLiteral(Ctx, 10);
6658ec6e09SChris Cotter     ParenExpr *PE =
6758ec6e09SChris Cotter         new (Ctx) ParenExpr(SourceLocation{}, SourceLocation{}, IntExpr);
6858ec6e09SChris Cotter     EXPECT_EQ(IntExpr, IgnoreExprNodes(PE, IgnoreParens{}));
6958ec6e09SChris Cotter   }
7058ec6e09SChris Cotter 
7158ec6e09SChris Cotter   {
7258ec6e09SChris Cotter     IgnoreParens CB{};
73*3c42e10aSReid Kleckner     auto *IntExpr = createIntLiteral(Ctx, 10);
7458ec6e09SChris Cotter     ParenExpr *PE =
7558ec6e09SChris Cotter         new (Ctx) ParenExpr(SourceLocation{}, SourceLocation{}, IntExpr);
7658ec6e09SChris Cotter     EXPECT_EQ(nullptr, IgnoreExprNodes(PE, CB));
7758ec6e09SChris Cotter   }
7858ec6e09SChris Cotter }
79*3c42e10aSReid Kleckner 
TEST(ASTExpr,InitListIsConstantInitialized)80*3c42e10aSReid Kleckner TEST(ASTExpr, InitListIsConstantInitialized) {
81*3c42e10aSReid Kleckner   auto AST = buildASTFromCode(R"cpp(
82*3c42e10aSReid Kleckner     struct Empty {};
83*3c42e10aSReid Kleckner     struct Foo : Empty { int x, y; };
84*3c42e10aSReid Kleckner     int gv;
85*3c42e10aSReid Kleckner   )cpp");
86*3c42e10aSReid Kleckner   ASTContext &Ctx = AST->getASTContext();
87*3c42e10aSReid Kleckner   const CXXRecordDecl *Empty = getCXXRecordDeclNode(AST.get(), "Empty");
88*3c42e10aSReid Kleckner   const CXXRecordDecl *Foo = getCXXRecordDeclNode(AST.get(), "Foo");
89*3c42e10aSReid Kleckner 
90*3c42e10aSReid Kleckner   SourceLocation Loc{};
91*3c42e10aSReid Kleckner   InitListExpr *BaseInit = new (Ctx) InitListExpr(Ctx, Loc, {}, Loc);
92*3c42e10aSReid Kleckner   BaseInit->setType(Ctx.getRecordType(Empty));
93*3c42e10aSReid Kleckner   Expr *Exprs[3] = {
94*3c42e10aSReid Kleckner       BaseInit,
95*3c42e10aSReid Kleckner       createIntLiteral(Ctx, 13),
96*3c42e10aSReid Kleckner       createIntLiteral(Ctx, 42),
97*3c42e10aSReid Kleckner   };
98*3c42e10aSReid Kleckner   InitListExpr *FooInit = new (Ctx) InitListExpr(Ctx, Loc, Exprs, Loc);
99*3c42e10aSReid Kleckner   FooInit->setType(Ctx.getRecordType(Foo));
100*3c42e10aSReid Kleckner   EXPECT_TRUE(FooInit->isConstantInitializer(Ctx, false));
101*3c42e10aSReid Kleckner 
102*3c42e10aSReid Kleckner   // Replace the last initializer with something non-constant and make sure
103*3c42e10aSReid Kleckner   // this returns false. Previously we had a bug where we didn't count base
104*3c42e10aSReid Kleckner   // initializers, and only iterated over fields.
105*3c42e10aSReid Kleckner   const VarDecl *GV = getVariableNode(AST.get(), "gv");
106*3c42e10aSReid Kleckner   auto *Ref = new (Ctx) DeclRefExpr(Ctx, const_cast<VarDecl *>(GV), false,
107*3c42e10aSReid Kleckner                                     Ctx.IntTy, VK_LValue, Loc);
108*3c42e10aSReid Kleckner   (void)FooInit->updateInit(Ctx, 2, Ref);
109*3c42e10aSReid Kleckner   EXPECT_FALSE(FooInit->isConstantInitializer(Ctx, false));
110*3c42e10aSReid Kleckner }
111