//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the AnalysisManager class that manages the data and policy
// for path sensitive analysis.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_GR_ANALYSISMANAGER_H
#define LLVM_CLANG_GR_ANALYSISMANAGER_H

#include "clang/Analysis/AnalysisContext.h"
#include "clang/Frontend/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"

namespace clang {

namespace ento {
  class CheckerManager;

class AnalysisManager : public BugReporterData {
  virtual void anchor();
  AnalysisDeclContextManager AnaCtxMgr;

  ASTContext &Ctx;
  DiagnosticsEngine &Diags;
  const LangOptions &LangOpts;

  OwningPtr<PathDiagnosticConsumer> PD;

  // Configurable components creators.
  StoreManagerCreator CreateStoreMgr;
  ConstraintManagerCreator CreateConstraintMgr;

  CheckerManager *CheckerMgr;

  enum AnalysisScope { ScopeTU, ScopeDecl } AScope;

  /// \brief The maximum number of exploded nodes the analyzer will generate.
  unsigned MaxNodes;

  /// \brief The maximum number of times the analyzer visits a block.
  unsigned MaxVisit;

  bool VisualizeEGDot;
  bool VisualizeEGUbi;
  AnalysisPurgeMode PurgeDead;

  /// \brief The flag regulates if we should eagerly assume evaluations of
  /// conditionals, thus, bifurcating the path.
  ///
  /// EagerlyAssume - A flag indicating how the engine should handle
  ///   expressions such as: 'x = (y != 0)'.  When this flag is true then
  ///   the subexpression 'y != 0' will be eagerly assumed to be true or false,
  ///   thus evaluating it to the integers 0 or 1 respectively.  The upside
  ///   is that this can increase analysis precision until we have a better way
  ///   to lazily evaluate such logic.  The downside is that it eagerly
  ///   bifurcates paths.
  bool EagerlyAssume;
  bool TrimGraph;
  bool EagerlyTrimEGraph;

public:
  // \brief inter-procedural analysis mode.
  AnalysisIPAMode IPAMode;

  // Settings for inlining tuning.
  /// \brief The inlining stack depth limit.
  unsigned InlineMaxStackDepth;
  /// \brief The max number of basic blocks in a function being inlined.
  unsigned InlineMaxFunctionSize;
  /// \brief The mode of function selection used during inlining.
  AnalysisInliningMode InliningMode;

  /// \brief Do not re-analyze paths leading to exhausted nodes with a different
  /// strategy. We get better code coverage when retry is enabled.
  bool NoRetryExhausted;

public:
  AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, 
                  const LangOptions &lang, PathDiagnosticConsumer *pd,
                  StoreManagerCreator storemgr,
                  ConstraintManagerCreator constraintmgr, 
                  CheckerManager *checkerMgr,
                  unsigned maxnodes, unsigned maxvisit,
                  bool vizdot, bool vizubi, AnalysisPurgeMode purge,
                  bool eager, bool trim,
                  bool useUnoptimizedCFG,
                  bool addImplicitDtors, bool addInitializers,
                  bool eagerlyTrimEGraph,
                  AnalysisIPAMode ipa,
                  unsigned inlineMaxStack,
                  unsigned inlineMaxFunctionSize,
                  AnalysisInliningMode inliningMode,
                  bool NoRetry);

  /// Construct a clone of the given AnalysisManager with the given ASTContext
  /// and DiagnosticsEngine.
  AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
                  AnalysisManager &ParentAM);

  ~AnalysisManager() { FlushDiagnostics(); }
  
  void ClearContexts() {
    AnaCtxMgr.clear();
  }
  
  AnalysisDeclContextManager& getAnalysisDeclContextManager() {
    return AnaCtxMgr;
  }

  StoreManagerCreator getStoreManagerCreator() {
    return CreateStoreMgr;
  }

  ConstraintManagerCreator getConstraintManagerCreator() {
    return CreateConstraintMgr;
  }

  CheckerManager *getCheckerManager() const { return CheckerMgr; }

  virtual ASTContext &getASTContext() {
    return Ctx;
  }

  virtual SourceManager &getSourceManager() {
    return getASTContext().getSourceManager();
  }

  virtual DiagnosticsEngine &getDiagnostic() {
    return Diags;
  }

  const LangOptions &getLangOpts() const {
    return LangOpts;
  }

  virtual PathDiagnosticConsumer *getPathDiagnosticConsumer() {
    return PD.get();
  }
  
  void FlushDiagnostics() {
    if (PD.get())
      PD->FlushDiagnostics(0);
  }

  unsigned getMaxNodes() const { return MaxNodes; }

  unsigned getMaxVisit() const { return MaxVisit; }

  bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }

  bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }

  bool shouldVisualize() const {
    return VisualizeEGDot || VisualizeEGUbi;
  }

  bool shouldEagerlyTrimExplodedGraph() const { return EagerlyTrimEGraph; }

  bool shouldTrimGraph() const { return TrimGraph; }

  AnalysisPurgeMode getPurgeMode() const { return PurgeDead; }

  bool shouldEagerlyAssume() const { return EagerlyAssume; }

  bool shouldInlineCall() const { return (IPAMode == Inlining); }

  CFG *getCFG(Decl const *D) {
    return AnaCtxMgr.getContext(D)->getCFG();
  }

  template <typename T>
  T *getAnalysis(Decl const *D) {
    return AnaCtxMgr.getContext(D)->getAnalysis<T>();
  }

  ParentMap &getParentMap(Decl const *D) {
    return AnaCtxMgr.getContext(D)->getParentMap();
  }

  AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) {
    return AnaCtxMgr.getContext(D);
  }

  AnalysisDeclContext *getAnalysisDeclContext(const Decl *D, idx::TranslationUnit *TU) {
    return AnaCtxMgr.getContext(D, TU);
  }

};

} // enAnaCtxMgrspace

} // end clang namespace

#endif
