#ifndef __FINALIZER__ANALYSIS__HPP
#define __FINALIZER__ANALYSIS__HPP

#include "DataFlow.hpp"
#include "DeallocatorInfo.hpp"
#include "CommonTypes.hpp"

#include "llvm/Pass.h"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Support/InstVisitor.h"

#include <boost/scoped_ptr.hpp>

namespace llvm
{
  class Function;
  class BasicBlock;
}

class AliasHelper;

/*!
  Determine which function parameters are *finalized*

  For each pointer parameter p of function f, p is finalized
  iff f invokes a finalizer on p along all execution paths.

  This is conceptually a bitvector dataflow analysis.
 */
struct FinalizerAnalysis : public llvm::InstVisitor<FinalizerAnalysis>,
                           public DataFlowIntermediate<deallocator_info>,
                           public llvm::CallGraphSCCPass
{
  static char ID;
  results_t * _res;
  typedef std::map<const llvm::BasicBlock*, deallocator_info> block_map;

public:
  FinalizerAnalysis(results_t * res = NULL);
  
  // Visitor
  void visitCallInst(llvm::CallInst &CI);

  // DataFlow
  virtual deallocator_info* join(deallocator_info * accum,
                                 deallocator_info * item);
  virtual deallocator_info transfer(const block_map & current,
                                    deallocator_info & inputStates,
                                    const llvm::BasicBlock* bb);

  // CallGraphSCCPass
  virtual bool onInitialize(llvm::CallGraph & CG);
  virtual bool runOnSCC(const std::vector<llvm::CallGraphNode *> &SCCM);
  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const;

private:
  void resetStateVariables();
  void checkDeallocator(llvm::Function &F);
  value_set deallocatedArguments(llvm::Function &F);
  
  void checkArgument(deallocator_info & accum,
                     const llvm::CallInst * ci,
                     const llvm::Value * arg);
  bool argAliasesVararg(const llvm::Value * arg,
                        const llvm::CallInst * ci);
  bool isAliasOfVFreedInBB(const block_map & m,
                           const llvm::Value * v,
                           const llvm::BasicBlock * bb);
  const llvm::Value * newlyNull(const block_map & m,
                                const llvm::BasicBlock * bb);
  
private:
  boost::scoped_ptr<AliasHelper> _AH;

  // To reset
  value_set calls;
  llvm::BasicBlock* _Entry;
};
#endif // __FINALIZER__ANALYSIS__HPP
