//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
namespace Microsoft.AbstractInterpretationFramework
{
using System.Diagnostics.Contracts;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AbstractInterpretationFramework;
using Microsoft.AbstractInterpretationFramework.Collections;
using Microsoft.Boogie;
using IMutableSet = Microsoft.Boogie.Set;
using HashSet = Microsoft.Boogie.Set;
using ISet = Microsoft.Boogie.Set;
///
/// Creates a lattice that works for several variables given a MicroLattice. Assumes
/// if one variable is bottom, then all variables are bottom.
///
public class VariableMapLattice : Lattice
{
private class Elt : Element
{
///
/// IsBottom(e) iff e.constraints == null
///
/*MayBeNull*/
private IFunctionalMap constraints; // of type IVariable -> LATTICE_ELEMENT
public IFunctionalMap Constraints
{
get
{
return this.constraints;
}
}
private Elt(bool top) {
if (top) {
this.constraints = FunctionalHashtable.Empty;
} else {
this.constraints = null;
}
}
public override Element/*!*/ Clone() {
Contract.Ensures(Contract.Result() != null);
return new Elt(this.constraints);
}
[Pure]
public override string/*!*/ ToString() {
Contract.Ensures(Contract.Result() != null);
if (constraints == null) {
return "";
}
string s = "[";
string sep = "";
foreach(IVariable/*!*/ v in cce.NonNull(constraints.Keys)){
Contract.Assert(v != null);
Element m = (Element)constraints[v];
s += sep + v.Name + " -> " + m;
sep = ", ";
}
return s + "]";
}
public static Elt/*!*/ Top = new Elt(true);
public static Elt/*!*/ Bottom = new Elt(false);
[ContractInvariantMethod]
void ObjectInvariant()
{
Contract.Invariant(Top != null);
Contract.Invariant(Bottom != null);
}
public Elt(IFunctionalMap constraints)
{
this.constraints = constraints;
}
public bool IsBottom {
get {
return this.constraints == null;
}
}
public int Count { get { return this.constraints == null ? 0 : this.constraints.Count; } }
public IEnumerable/**//*!*/ Variables {
get {
Contract.Requires(!this.IsBottom);
Contract.Ensures(Contract.Result() != null);
Contract.Assume(this.constraints != null);
return cce.NonNull(this.constraints.Keys);
}
}
public IEnumerable/**//*!*/ SortedVariables(/*maybe null*/ IComparer variableComparer) {
Contract.Ensures(Contract.Result() != null);
if (variableComparer == null) {
return Variables;
} else {
ArrayList /*IVariable*/ vars = new ArrayList /*IVariable*/ (Count);
foreach (IVariable variable in Variables) {
vars.Add(variable);
}
vars.Sort(variableComparer);
return vars;
}
}
public Element Lookup(IVariable v)
{
if ((v == null) || (this.constraints == null)) { return null; }
return (Element)this.constraints[v];
}
public Element this [IVariable/*!*/ key] {
get{
Contract.Requires(!this.IsBottom);
Contract.Requires(key != null);
Contract.Assume(this.constraints != null);
return (Element)constraints[key];
}
}
///
/// Add a new entry in the functional map: var --> value.
/// If the variable is already there, throws an exception
///
public Elt/*!*/ Add(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice){
Contract.Requires(microLattice != null);
Contract.Requires(value != null);
Contract.Requires(var != null);
Contract.Requires((!this.IsBottom));
Contract.Ensures(Contract.Result() != null);
Contract.Assume(this.constraints != null);
Contract.Assert(!this.constraints.Contains(var));
if (microLattice.IsBottom(value)) { return Bottom; }
if (microLattice.IsTop(value)) { return this.Remove(var, microLattice); }
return new Elt(this.constraints.Add(var, value));
}
///
/// Set the value of the variable in the functional map
/// If the variable is not already there, throws an exception
///
public Elt/*!*/ Set(IVariable/*!*/ var, Element/*!*/ value, MicroLattice/*!*/ microLattice){
Contract.Requires(microLattice != null);
Contract.Requires(value != null);
Contract.Requires(var != null);
Contract.Ensures(Contract.Result() != null);
if(microLattice.IsBottom(value)) { return Bottom; }
if(microLattice.IsTop(value)) { return this.Remove(var, microLattice); }
Contract.Assume(this.constraints != null);
Contract.Assert(this.constraints.Contains(var));
// this.constraints[var] = value;
IFunctionalMap newMap = this.constraints.Set(var, value);
return new Elt(newMap);
}
public Elt/*!*/ Remove(IVariable/*!*/ var, MicroLattice microLattice){
Contract.Requires(var != null);
Contract.Ensures(Contract.Result() != null);
if (this.IsBottom) { return this; }
Contract.Assume(this.constraints != null);
return new Elt(this.constraints.Remove(var));
}
public Elt/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName, MicroLattice/*!*/ microLattice){
Contract.Requires(microLattice != null);
Contract.Requires(newName != null);
Contract.Requires(oldName != null);
Contract.Requires((!this.IsBottom));
Contract.Ensures(Contract.Result() != null);
Element value = this[oldName];
if (value == null) { return this; } // 'oldName' isn't in the map, so neither will be 'newName'
Contract.Assume(this.constraints != null);
IFunctionalMap newMap = this.constraints.Remove(oldName);
newMap = newMap.Add(newName, value);
return new Elt(newMap);
}
[Pure]
public override ICollection/*!*/ FreeVariables() {
Contract.Ensures(cce.NonNullElements(Contract.Result>()));
throw new System.NotImplementedException();
}
} // class
private readonly MicroLattice/*!*/ microLattice;
private readonly IPropExprFactory/*!*/ propExprFactory;
[ContractInvariantMethod]
void ObjectInvariant()
{
Contract.Invariant(microLattice != null);
Contract.Invariant(propExprFactory != null);
}
private readonly /*maybe null*/IComparer variableComparer;
public VariableMapLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory, MicroLattice/*!*/ microLattice, /*maybe null*/IComparer variableComparer)
: base(valueExprFactory){
Contract.Requires(microLattice != null);
Contract.Requires(valueExprFactory != null);
Contract.Requires(propExprFactory != null);
this.propExprFactory = propExprFactory;
this.microLattice = microLattice;
this.variableComparer = variableComparer;
// base(valueExprFactory);
}
protected override object/*!*/ UniqueId{
get{
Contract.Ensures(Contract.Result