1 //===- unittests/AST/ASTExprTest.cpp --- AST Expr tests -------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains tests for AST Expr related methods.
11 //===----------------------------------------------------------------------===//
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"
21 using namespace clang
;
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
;
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
,
35 const CXXRecordDecl
*getCXXRecordDeclNode(ASTUnit
*AST
,
36 const std::string
&Name
) {
38 match(cxxRecordDecl(hasName(Name
)).bind("record"), AST
->getASTContext());
39 EXPECT_FALSE(Result
.empty());
40 return Result
[0].getNodeAs
<CXXRecordDecl
>("record");
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");
49 TEST(ASTExpr
, IgnoreExprCallbackForwarded
) {
50 constexpr char Code
[] = "";
51 auto AST
= tooling::buildASTFromCodeWithArgs(Code
, /*Args=*/{"-std=c++20"});
52 ASTContext
&Ctx
= AST
->getASTContext();
55 Expr
*operator()(Expr
*E
) & { return nullptr; }
56 Expr
*operator()(Expr
*E
) && {
57 if (auto *PE
= dyn_cast
<ParenExpr
>(E
)) {
58 return PE
->getSubExpr();
65 auto *IntExpr
= createIntLiteral(Ctx
, 10);
67 new (Ctx
) ParenExpr(SourceLocation
{}, SourceLocation
{}, IntExpr
);
68 EXPECT_EQ(IntExpr
, IgnoreExprNodes(PE
, IgnoreParens
{}));
73 auto *IntExpr
= createIntLiteral(Ctx
, 10);
75 new (Ctx
) ParenExpr(SourceLocation
{}, SourceLocation
{}, IntExpr
);
76 EXPECT_EQ(nullptr, IgnoreExprNodes(PE
, CB
));
80 TEST(ASTExpr
, InitListIsConstantInitialized
) {
81 auto AST
= buildASTFromCode(R
"cpp(
83 struct Foo : Empty { int x, y; };
86 ASTContext
&Ctx
= AST
->getASTContext();
87 const CXXRecordDecl
*Empty
= getCXXRecordDeclNode(AST
.get(), "Empty");
88 const CXXRecordDecl
*Foo
= getCXXRecordDeclNode(AST
.get(), "Foo");
91 InitListExpr
*BaseInit
= new (Ctx
) InitListExpr(Ctx
, Loc
, {}, Loc
);
92 BaseInit
->setType(Ctx
.getRecordType(Empty
));
95 createIntLiteral(Ctx
, 13),
96 createIntLiteral(Ctx
, 42),
98 InitListExpr
*FooInit
= new (Ctx
) InitListExpr(Ctx
, Loc
, Exprs
, Loc
);
99 FooInit
->setType(Ctx
.getRecordType(Foo
));
100 EXPECT_TRUE(FooInit
->isConstantInitializer(Ctx
, false));
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));