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
21using namespace clang;
22
23using clang::ast_matchers::cxxRecordDecl;
24using clang::ast_matchers::hasName;
25using clang::ast_matchers::match;
26using clang::ast_matchers::varDecl;
27using clang::tooling::buildASTFromCode;
28
29static 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
35const CXXRecordDecl *getCXXRecordDeclNode(ASTUnit *AST,
36 const std::string &Name) {
37 auto Result =
38 match(Matcher: cxxRecordDecl(hasName(Name)).bind(ID: "record"), Context&: AST->getASTContext());
39 EXPECT_FALSE(Result.empty());
40 return Result[0].getNodeAs<CXXRecordDecl>(ID: "record");
41}
42
43const VarDecl *getVariableNode(ASTUnit *AST, const std::string &Name) {
44 auto Result = match(Matcher: varDecl(hasName(Name)).bind(ID: "var"), Context&: AST->getASTContext());
45 EXPECT_EQ(Result.size(), 1u);
46 return Result[0].getNodeAs<VarDecl>(ID: "var");
47}
48
49TEST(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>(Val: E)) {
58 return PE->getSubExpr();
59 }
60 return E;
61 }
62 };
63
64 {
65 auto *IntExpr = createIntLiteral(Ctx, Value: 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, Value: 10);
74 ParenExpr *PE =
75 new (Ctx) ParenExpr(SourceLocation{}, SourceLocation{}, IntExpr);
76 EXPECT_EQ(nullptr, IgnoreExprNodes(PE, CB));
77 }
78}
79
80TEST(ASTExpr, InitListIsConstantInitialized) {
81 auto AST = buildASTFromCode(Code: 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: AST.get(), Name: "Empty");
88 const CXXRecordDecl *Foo = getCXXRecordDeclNode(AST: AST.get(), Name: "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, Value: 13),
96 createIntLiteral(Ctx, Value: 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: AST.get(), Name: "gv");
106 auto *Ref = new (Ctx) DeclRefExpr(Ctx, const_cast<VarDecl *>(GV), false,
107 Ctx.IntTy, VK_LValue, Loc);
108 (void)FooInit->updateInit(C: Ctx, Init: 2, expr: Ref);
109 EXPECT_FALSE(FooInit->isConstantInitializer(Ctx, false));
110}
111

source code of clang/unittests/AST/ASTExprTest.cpp