/*******************************************************************\

Module: Pointer Dereferencing

Author: Daniel Kroening, kroening@cs.cmu.edu

\*******************************************************************/

#ifndef CPROVER_POINTER_ANALYSIS_DEREFERENCE_H
#define CPROVER_POINTER_ANALYSIS_DEREFERENCE_H

#include <set>

#include <expr.h>
#include <hash_cont.h>
#include <guard.h>
#include <namespace.h>
#include <options.h>

class dereference_callbackt
{
public:
  virtual ~dereference_callbackt()
  {
  }

  virtual bool is_valid_object(const irep_idt &identifier)=0;

  virtual void dereference_failure(
    const std::string &property,
    const std::string &msg,
    const guardt &guard)=0;

  typedef hash_set_cont<exprt, irep_hash> expr_sett;

  virtual void get_value_set(const exprt &expr, expr_sett &value_set)=0;
  
  virtual bool has_failed_symbol(
    const exprt &expr,
    const symbolt *&symbol)=0;
};

class dereferencet
{
public:
  dereferencet(
    const namespacet &_ns,
    contextt &_new_context,
    const optionst &_options,
    dereference_callbackt &_dereference_callback):
    ns(_ns),
    new_context(_new_context),
    options(_options),
    dereference_callback(_dereference_callback)
  { }

  virtual ~dereferencet() { }

  virtual void dereference(
    exprt &dest,
    const guardt &guard);
    
  virtual void add_checks(
    const exprt &dest,
    const guardt &guard);

  bool has_dereference(const exprt &expr) const;

  typedef hash_set_cont<exprt, irep_hash> expr_sett;

private:
  const namespacet &ns;
  contextt &new_context;
  const optionst &options;
  dereference_callbackt &dereference_callback;
  static unsigned invalid_counter;

  virtual void get_points_to_set(
    const exprt &dest,
    const exprt &offset,
    expr_sett &points_to_set);

  bool dereference_type_compare(
    exprt &object,
    const typet &dereference_type) const;

  void offset_sum(
    exprt &dest,
    const exprt &offset) const;
  
  void build_reference_to(
    const exprt &what, 
    const exprt &deref_expr,
    const typet &type,
    const exprt &offset,
    exprt &value,
    exprt &pointer_guard,
    const guardt &guard);

  bool get_value_guard(
    const exprt &symbol,
    const exprt &premise,
    exprt &value);
                                  
  void get_reference_set(
    const exprt &dest,
    const exprt &offset,
    expr_sett &reference_set);

  const exprt &get_symbol(const exprt &object) const;
  
  void bounds_check(const exprt &expr, const guardt &guard);
  void valid_check(const exprt &expr, const guardt &guard);

  bool memory_model(
    exprt &value,
    const typet &type,
    const guardt &guard,
    exprt &new_offset);
};

void dereference(
  const namespacet &ns,
  const class value_sett &value_set,
  exprt &dest);

#endif
