1651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
2651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
3651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//                     The LLVM Compiler Infrastructure
4651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
5651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// This file is distributed under the University of Illinois Open Source
6651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// License. See LICENSE.TXT for details.
7651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
8651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===----------------------------------------------------------------------===//
9651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
10651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// \file
11651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// \brief Unit tests for evaluation of constant initializers.
12651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
13651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===----------------------------------------------------------------------===//
14651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
15651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <map>
16651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <string>
17651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
18651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/AST/ASTConsumer.h"
19651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/AST/ASTContext.h"
20651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/AST/RecursiveASTVisitor.h"
21651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/Tooling/Tooling.h"
22651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "gtest/gtest.h"
23651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
24651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/AST/ASTConsumer.h"
25651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
26651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace clang::tooling;
27651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
28651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
29651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// For each variable name encountered, whether its initializer was a
30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// constant.
31651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinestypedef std::map<std::string, bool> VarInfoMap;
32651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
33651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines/// \brief Records information on variable initializers to a map.
34651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass EvaluateConstantInitializersVisitor
35651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    : public clang::RecursiveASTVisitor<EvaluateConstantInitializersVisitor> {
36651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines public:
37651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)
38651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : VarInfo(VarInfo) {}
39651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
40651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// \brief Checks that isConstantInitializer and EvaluateAsRValue agree
41651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// and don't crash.
42651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ///
43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// For each VarDecl with an initializer this also records in VarInfo
44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  /// whether the initializer could be evaluated as a constant.
45651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  bool VisitVarDecl(const clang::VarDecl *VD) {
46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (const clang::Expr *Init = VD->getInit()) {
47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      clang::Expr::EvalResult Result;
48651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      bool WasEvaluated = Init->EvaluateAsRValue(Result, VD->getASTContext());
49651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      VarInfo[VD->getNameAsString()] = WasEvaluated;
50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      EXPECT_EQ(WasEvaluated, Init->isConstantInitializer(VD->getASTContext(),
51651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                                          false /*ForRef*/));
52651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
53651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return true;
54651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
55651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
56651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines private:
57651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  VarInfoMap &VarInfo;
58651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
59651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
60651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass EvaluateConstantInitializersAction : public clang::ASTFrontendAction {
61651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines public:
62651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
63651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                                        llvm::StringRef FilePath) override {
64651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return new Consumer;
65651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
66651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
67651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines private:
68651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  class Consumer : public clang::ASTConsumer {
69651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines   public:
70651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ~Consumer() override {}
71651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
72651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    void HandleTranslationUnit(clang::ASTContext &Ctx) override {
73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      VarInfoMap VarInfo;
74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      EvaluateConstantInitializersVisitor Evaluator(VarInfo);
75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
76651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      EXPECT_EQ(2u, VarInfo.size());
77651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      EXPECT_FALSE(VarInfo["Dependent"]);
78651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      EXPECT_TRUE(VarInfo["Constant"]);
79651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      EXPECT_EQ(2u, VarInfo.size());
80651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
81651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  };
82651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
83651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
84651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
85651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) {
86651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // This is a regression test; the AST library used to trigger assertion
87651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // failures because it assumed that the type of initializers was always
88651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // known (which is true only after template instantiation).
89651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::string ModesToTest[] = {"-std=c++03", "-std=c++11", "-std=c++1y"};
90651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  for (std::string const &Mode : ModesToTest) {
91651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::vector<std::string> Args(1, Mode);
92651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    Args.push_back("-fno-delayed-template-parsing");
93651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ASSERT_TRUE(runToolOnCodeWithArgs(
94651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      new EvaluateConstantInitializersAction(),
95651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "template <typename T>"
96651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "struct vector {"
97651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  explicit vector(int size);"
98651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "};"
99651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "template <typename R>"
100651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "struct S {"
101651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  vector<R> intervals() const {"
102651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    vector<R> Dependent(2);"
103651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    return Dependent;"
104651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  }"
105651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "};"
106651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "void doSomething() {"
107651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  int Constant = 2 + 2;"
108651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  (void) Constant;"
109651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "}",
110651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Args));
111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
112651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
113