111 lines · cpp
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-exception6//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(cxxRecordDecl(hasName(Name)).bind("record"), AST->getASTContext());39 EXPECT_FALSE(Result.empty());40 return Result[0].getNodeAs<CXXRecordDecl>("record");41}42 43const 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 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>(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 80TEST(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.getCanonicalTagType(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.getCanonicalTagType(Foo));100 EXPECT_TRUE(FooInit->isConstantInitializer(Ctx, false));101 102 // Replace the last initializer with something non-constant and make sure103 // this returns false. Previously we had a bug where we didn't count base104 // 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