1*67e74705SXin Li //===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // \file
11*67e74705SXin Li // \brief Unit tests for evaluation of constant initializers.
12*67e74705SXin Li //
13*67e74705SXin Li //===----------------------------------------------------------------------===//
14*67e74705SXin Li
15*67e74705SXin Li #include "clang/AST/ASTConsumer.h"
16*67e74705SXin Li #include "clang/AST/ASTConsumer.h"
17*67e74705SXin Li #include "clang/AST/ASTContext.h"
18*67e74705SXin Li #include "clang/AST/RecursiveASTVisitor.h"
19*67e74705SXin Li #include "clang/Tooling/Tooling.h"
20*67e74705SXin Li #include "gtest/gtest.h"
21*67e74705SXin Li #include <map>
22*67e74705SXin Li #include <string>
23*67e74705SXin Li
24*67e74705SXin Li using namespace clang::tooling;
25*67e74705SXin Li
26*67e74705SXin Li namespace {
27*67e74705SXin Li // For each variable name encountered, whether its initializer was a
28*67e74705SXin Li // constant.
29*67e74705SXin Li typedef std::map<std::string, bool> VarInfoMap;
30*67e74705SXin Li
31*67e74705SXin Li /// \brief Records information on variable initializers to a map.
32*67e74705SXin Li class EvaluateConstantInitializersVisitor
33*67e74705SXin Li : public clang::RecursiveASTVisitor<EvaluateConstantInitializersVisitor> {
34*67e74705SXin Li public:
EvaluateConstantInitializersVisitor(VarInfoMap & VarInfo)35*67e74705SXin Li explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)
36*67e74705SXin Li : VarInfo(VarInfo) {}
37*67e74705SXin Li
38*67e74705SXin Li /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree
39*67e74705SXin Li /// and don't crash.
40*67e74705SXin Li ///
41*67e74705SXin Li /// For each VarDecl with an initializer this also records in VarInfo
42*67e74705SXin Li /// whether the initializer could be evaluated as a constant.
VisitVarDecl(const clang::VarDecl * VD)43*67e74705SXin Li bool VisitVarDecl(const clang::VarDecl *VD) {
44*67e74705SXin Li if (const clang::Expr *Init = VD->getInit()) {
45*67e74705SXin Li clang::Expr::EvalResult Result;
46*67e74705SXin Li bool WasEvaluated = Init->EvaluateAsRValue(Result, VD->getASTContext());
47*67e74705SXin Li VarInfo[VD->getNameAsString()] = WasEvaluated;
48*67e74705SXin Li EXPECT_EQ(WasEvaluated, Init->isConstantInitializer(VD->getASTContext(),
49*67e74705SXin Li false /*ForRef*/));
50*67e74705SXin Li }
51*67e74705SXin Li return true;
52*67e74705SXin Li }
53*67e74705SXin Li
54*67e74705SXin Li private:
55*67e74705SXin Li VarInfoMap &VarInfo;
56*67e74705SXin Li };
57*67e74705SXin Li
58*67e74705SXin Li class EvaluateConstantInitializersAction : public clang::ASTFrontendAction {
59*67e74705SXin Li public:
60*67e74705SXin Li std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance & Compiler,llvm::StringRef FilePath)61*67e74705SXin Li CreateASTConsumer(clang::CompilerInstance &Compiler,
62*67e74705SXin Li llvm::StringRef FilePath) override {
63*67e74705SXin Li return llvm::make_unique<Consumer>();
64*67e74705SXin Li }
65*67e74705SXin Li
66*67e74705SXin Li private:
67*67e74705SXin Li class Consumer : public clang::ASTConsumer {
68*67e74705SXin Li public:
~Consumer()69*67e74705SXin Li ~Consumer() override {}
70*67e74705SXin Li
HandleTranslationUnit(clang::ASTContext & Ctx)71*67e74705SXin Li void HandleTranslationUnit(clang::ASTContext &Ctx) override {
72*67e74705SXin Li VarInfoMap VarInfo;
73*67e74705SXin Li EvaluateConstantInitializersVisitor Evaluator(VarInfo);
74*67e74705SXin Li Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
75*67e74705SXin Li EXPECT_EQ(2u, VarInfo.size());
76*67e74705SXin Li EXPECT_FALSE(VarInfo["Dependent"]);
77*67e74705SXin Li EXPECT_TRUE(VarInfo["Constant"]);
78*67e74705SXin Li EXPECT_EQ(2u, VarInfo.size());
79*67e74705SXin Li }
80*67e74705SXin Li };
81*67e74705SXin Li };
82*67e74705SXin Li }
83*67e74705SXin Li
TEST(EvaluateAsRValue,FailsGracefullyForUnknownTypes)84*67e74705SXin Li TEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) {
85*67e74705SXin Li // This is a regression test; the AST library used to trigger assertion
86*67e74705SXin Li // failures because it assumed that the type of initializers was always
87*67e74705SXin Li // known (which is true only after template instantiation).
88*67e74705SXin Li std::string ModesToTest[] = {"-std=c++03", "-std=c++11", "-std=c++1y"};
89*67e74705SXin Li for (std::string const &Mode : ModesToTest) {
90*67e74705SXin Li std::vector<std::string> Args(1, Mode);
91*67e74705SXin Li Args.push_back("-fno-delayed-template-parsing");
92*67e74705SXin Li ASSERT_TRUE(runToolOnCodeWithArgs(
93*67e74705SXin Li new EvaluateConstantInitializersAction(),
94*67e74705SXin Li "template <typename T>"
95*67e74705SXin Li "struct vector {"
96*67e74705SXin Li " explicit vector(int size);"
97*67e74705SXin Li "};"
98*67e74705SXin Li "template <typename R>"
99*67e74705SXin Li "struct S {"
100*67e74705SXin Li " vector<R> intervals() const {"
101*67e74705SXin Li " vector<R> Dependent(2);"
102*67e74705SXin Li " return Dependent;"
103*67e74705SXin Li " }"
104*67e74705SXin Li "};"
105*67e74705SXin Li "void doSomething() {"
106*67e74705SXin Li " int Constant = 2 + 2;"
107*67e74705SXin Li " (void) Constant;"
108*67e74705SXin Li "}",
109*67e74705SXin Li Args));
110*67e74705SXin Li }
111*67e74705SXin Li }
112