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

Module: Value Set

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

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

#ifndef CPROVER_POINTER_ANALYSIS_GOTO_PROGRAM_DEREFERENCE_H
#define CPROVER_POINTER_ANALYSIS_GOTO_PROGRAM_DEREFERENCE_H

#include <namespace.h>
#include <goto-programs/goto_program.h>

#include "value_propagation.h"
#include "dereference.h"

class goto_program_dereferencet:protected dereference_callbackt
{
public:
  goto_program_dereferencet(
    const namespacet &_ns,
    contextt &_new_context,
    const optionst &_options):
    options(_options),
    ns(_ns),
    dereference(_ns, _new_context, _options, *this) { }

  void dereference_program(
    goto_programt &goto_program,
    const value_propagationt &value_propagation,
    bool checks_only=false);

  void dereference_program(
    goto_functionst &goto_functions,
    const value_propagationt &value_propagation,
    bool checks_only=false);

  void pointer_checks(
    goto_programt &goto_program,
    const value_propagationt &value_propagation);

  void pointer_checks(
    goto_functionst &goto_functions,
    const value_propagationt &value_propagation);

  void dereference_expression(
    goto_programt::const_targett target,
    exprt &expr,
    const value_propagationt &value_propagation);
    
  virtual ~goto_program_dereferencet()
  {
  }
    
protected:
  const optionst &options;
  const namespacet &ns;
  dereferencet dereference;

  virtual bool is_valid_object(const irep_idt &identifier);

  virtual bool has_failed_symbol(
    const exprt &expr,
    const symbolt *&symbol);

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

  virtual void get_value_set(
    const exprt &expr,
    value_sett::expr_sett &value_set);

  void dereference_instruction(
    goto_programt::targett target,
    const value_propagationt &value_propagation,
    bool checks_only=false);

protected:
  void dereference_rec(exprt &expr, guardt &guard);
  void dereference_expr(exprt &expr, bool checks_only);
  
  const value_sett *current_value_set;
  const std::set<irep_idt> *valid_local_variables;
  locationt dereference_location;
  
  std::set<exprt> assertions;
  goto_programt new_code;
};

void dereference(
  goto_programt::const_targett target,
  exprt &expr,
  const namespacet &ns,
  const value_propagationt &value_propagation);

void remove_pointers(
  goto_programt &goto_program,
  contextt &context,
  const optionst &options,
  const value_propagationt &value_propagation);

void pointer_checks(
  goto_programt &goto_program,
  const namespacet &ns,
  const optionst &options,
  const value_propagationt &value_propagation);

void pointer_checks(
  goto_functionst &goto_functions,
  const namespacet &ns,
  const optionst &options,
  const value_propagationt &value_propagation);

#endif
