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