//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
namespace Microsoft.AbstractInterpretationFramework {
using System;
using System.Diagnostics.Contracts;
using System.Collections;
using G = System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AbstractInterpretationFramework.Collections;
using Microsoft.Boogie;
using IMutableSet = Microsoft.Boogie.Set;
using ISet = Microsoft.Boogie.Set;
using HashSet = Microsoft.Boogie.Set;
using ArraySet = Microsoft.Boogie.Set;
///
/// Specifies the operations (e.g., join) on a mathematical lattice that depend
/// only on the elements of the lattice.
///
[ContractClass(typeof(MathematicalLatticeContracts))]
public abstract class MathematicalLattice {
#region Element
///
/// An element of the lattice. This class should be derived from in any
/// implementation of MathematicalLattice.
///
[ContractClass(typeof(ElementContracts))]
public abstract class Element : System.ICloneable {
///
/// Print out a debug-useful representation of the internal data structure of the lattice element.
///
public virtual void Dump(string/*!*/ msg) {
Contract.Requires(msg != null);
System.Console.WriteLine("Dump({0}) = {1}", msg, this);
}
public abstract Element/*!*/ Clone();
object/*!*/ System.ICloneable.Clone() {
return this.Clone();
}
public abstract G.ICollection/*!*/ FreeVariables();
}
[ContractClassFor(typeof(Element))]
public abstract class ElementContracts : Element {
public override Element Clone() {
Contract.Ensures(Contract.Result() != null);
throw new NotImplementedException();
}
public override System.Collections.Generic.ICollection FreeVariables() {
Contract.Ensures(cce.NonNullElements(Contract.Result>()));
Contract.Ensures(Contract.Result>().IsReadOnly);
throw new System.NotImplementedException();
}
}
#endregion
public abstract Element/*!*/ Top {
get;
}
public abstract Element/*!*/ Bottom {
get;
}
public abstract bool IsTop(Element/*!*/ e);
public abstract bool IsBottom(Element/*!*/ e);
///
/// Returns true if a <= this.
///
protected abstract bool AtMost(Element/*!*/ a, Element/*!*/ b);
/* The following cases are handled elsewhere and need not be considered in subclass. */
// requires a.GetType() == b.GetType();
// requires ! a.IsTop;
// requires ! a.IsBottom;
// requires ! b.IsTop;
// requires ! b.IsBottom;
protected Answer TrivialLowerThan(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
if (a.GetType() != b.GetType()) {
throw new System.InvalidOperationException(
"operands to <= must be of same Element type"
);
}
if (IsBottom(a)) {
return Answer.Yes;
}
if (IsTop(b)) {
return Answer.Yes;
}
if (IsTop(a)) {
return Answer.No;
}
if (IsBottom(b)) {
return Answer.No;
}
return Answer.Maybe;
}
// Is 'a' better information than 'b'?
//
public bool LowerThan(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
Answer ans = TrivialLowerThan(a, b);
return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, b);
}
// Is 'a' worse information than 'b'?
//
public bool HigherThan(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
return LowerThan(b, a);
}
// Are 'a' and 'b' equivalent?
//
public bool Equivalent(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
return LowerThan(a, b) && LowerThan(b, a);
}
public abstract Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b);
/* The following cases are handled elsewhere and need not be considered in subclass. */
// requires a.GetType() == b.GetType();
// requires ! a.IsTop;
// requires ! a.IsBottom;
// requires ! b.IsTop;
// requires ! b.IsBottom;
protected Element/*?*/ TrivialJoin(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
if (a.GetType() != b.GetType()) {
throw new System.InvalidOperationException(
"operands to Join must be of same Lattice.Element type"
);
}
if (IsTop(a)) {
return a;
}
if (IsTop(b)) {
return b;
}
if (IsBottom(a)) {
return b;
}
if (IsBottom(b)) {
return a;
}
return null;
}
public Element/*!*/ Join(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
Contract.Ensures(Contract.Result() != null);
Element/*?*/ r = TrivialJoin(a, b);
return r != null ? r : NontrivialJoin(a, b);
}
public abstract Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b)
/* The following cases are handled elsewhere and need not be considered in subclass. */
// requires a.GetType() == b.GetType();
// requires ! a.IsTop;
// requires ! a.IsBottom;
// requires ! b.IsTop;
// requires ! b.IsBottom;
;
protected Element/*?*/ TrivialMeet(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
if (a.GetType() != b.GetType()) {
throw new System.InvalidOperationException(
"operands to Meet must be of same Lattice.Element type"
);
}
if (IsTop(a)) {
return b;
}
if (IsTop(b)) {
return a;
}
if (IsBottom(a)) {
return a;
}
if (IsBottom(b)) {
return b;
}
return null;
}
public Element/*!*/ Meet(Element/*!*/ a, Element/*!*/ b) {
Contract.Requires(b != null);
Contract.Requires(a != null);
Contract.Ensures(Contract.Result() != null);
Element/*?*/ r = TrivialMeet(a, b);
return r != null ? r : NontrivialMeet(a, b);
}
public abstract Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b);
public virtual void Validate() {
Debug.Assert(IsTop(Top));
Debug.Assert(IsBottom(Bottom));
Debug.Assert(!IsBottom(Top));
Debug.Assert(!IsTop(Bottom));
Debug.Assert(LowerThan(Top, Top));
Debug.Assert(LowerThan(Bottom, Top));
Debug.Assert(LowerThan(Bottom, Bottom));
Debug.Assert(IsTop(Join(Top, Top)));
Debug.Assert(IsBottom(Join(Bottom, Bottom)));
}
}
[ContractClassFor(typeof(MathematicalLattice))]
public abstract class MathematicalLatticeContracts : MathematicalLattice {
public override MathematicalLattice.Element Top {
get {
Contract.Ensures(Contract.Result() != null);
throw new NotImplementedException();
}
}
public override MathematicalLattice.Element Bottom {
get {
Contract.Ensures(Contract.Result() != null);
throw new NotImplementedException();
}
}
public override bool IsTop(MathematicalLattice.Element e) {
Contract.Requires(e != null);
throw new NotImplementedException();
}
public override bool IsBottom(MathematicalLattice.Element e) {
Contract.Requires(e != null);
throw new NotImplementedException();
}
protected override bool AtMost(MathematicalLattice.Element a, MathematicalLattice.Element b) {
Contract.Requires(a != null);
Contract.Requires(b != null);
throw new NotImplementedException();
}
public override MathematicalLattice.Element NontrivialJoin(MathematicalLattice.Element a, MathematicalLattice.Element b) {
Contract.Requires(a != null);
Contract.Requires(b != null);
Contract.Ensures(Contract.Result() != null);
throw new NotImplementedException();
}
public override MathematicalLattice.Element NontrivialMeet(MathematicalLattice.Element a, MathematicalLattice.Element b) {
Contract.Requires(a != null);
Contract.Requires(b != null);
Contract.Ensures(Contract.Result() != null);
throw new NotImplementedException();
}
public override MathematicalLattice.Element Widen(MathematicalLattice.Element a, MathematicalLattice.Element b) {
Contract.Requires(a != null);
Contract.Requires(b != null);
Contract.Ensures(Contract.Result() != null);
throw new NotImplementedException();
}
}
///
/// Provides an abstract interface for the operations of a lattice specific
/// to abstract interpretation (i.e., that deals with the expression language).
///
[ContractClass(typeof(LatticeContracts))]
public abstract class Lattice : MathematicalLattice {
internal readonly IValueExprFactory/*!*/ valueExprFactory;
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(valueExprFactory != null);
}
public Lattice(IValueExprFactory/*!*/ valueExprFactory) {
Contract.Requires(valueExprFactory != null);
this.valueExprFactory = valueExprFactory;
// base();
}
#region Primitives that commands translate into
public abstract Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable);
public abstract Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName);
public abstract Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr);
#endregion
// TODO keep this?
// public Element! Eliminate(Element! e, VariableSeq! variables)
// {
// Lattice.Element result = e;
// foreach (IVariable var in variables)
// {
// result = this.Eliminate(result, var);
// }
// return result;
// }
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Note!
//
// Concrete classes that implement Lattice must implement one of the AtMost
// overloads. We provide here a default implementation for one given a "real"
// implementation of the other. Otherwise, there will be an infinite loop!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
protected override bool AtMost(Element/*!*/ a, Element/*!*/ b) {
//Contract.Requires(b != null);
//Contract.Requires(a != null);
return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
}
protected virtual bool AtMost(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
Contract.Requires(bToResult != null);
Contract.Requires(b != null);
Contract.Requires(aToResult != null);
Contract.Requires(a != null);
return AtMost(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult));
}
public bool LowerThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
Contract.Requires(bToResult != null);
Contract.Requires(b != null);
Contract.Requires(aToResult != null);
Contract.Requires(a != null);
Answer ans = TrivialLowerThan(a, b);
return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, aToResult, b, bToResult);
}
public bool HigherThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
Contract.Requires(bToResult != null);
Contract.Requires(b != null);
Contract.Requires(aToResult != null);
Contract.Requires(a != null);
return LowerThan(b, bToResult, a, aToResult);
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Note!
//
// Concrete classes that implement Lattice must implement one of the NontrivialJoin
// overloads. We provide here a default implementation for one given a "real"
// implementation of the other. Otherwise, there will be an infinite loop!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) {
//Contract.Requires(b != null);
//Contract.Requires(a != null);
Contract.Ensures(Contract.Result() != null);
return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
}
public virtual Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
Contract.Requires(bToResult != null);
Contract.Requires(b != null);
Contract.Requires(aToResult != null);
Contract.Requires(a != null);
Contract.Ensures(Contract.Result() != null);
return NontrivialJoin(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult));
}
public Element/*!*/ Join(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
Contract.Requires(bToResult != null);
Contract.Requires(b != null);
Contract.Requires(aToResult != null);
Contract.Requires(a != null);
Contract.Ensures(Contract.Result() != null);
Element/*?*/ r = TrivialJoin(a, b);
return r != null ? r : NontrivialJoin(a, aToResult, b, bToResult);
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Note!
//
// Concrete classes that implement Lattice must implement one of the Widen
// overloads. We provide here a default implementation for one given a "real"
// implementation of the other. Otherwise, there will be an infinite loop!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) {
//Contract.Requires(b != null);
//Contract.Requires(a != null);
Contract.Ensures(Contract.Result() != null);
return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
}
public virtual Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
Contract.Requires(bToResult != null);
Contract.Requires(b != null);
Contract.Requires(aToResult != null);
Contract.Requires(a != null);
Contract.Ensures(Contract.Result() != null);
return Widen(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult));
}
///
/// A default implementation of the given
/// the appropriate expression factories by calling CheckPredicate.
///
protected Answer DefaultCheckVariableDisequality(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valExprFactory, Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) {
Contract.Requires(propExprFactory != null);
Contract.Requires(valExprFactory != null);
Contract.Requires(e != null);
Contract.Requires(var1 != null);
Contract.Requires(var2 != null);
return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2)));
}
private Element/*!*/ ApplyCombineNameMap(Element/*!*/ e, ICombineNameMap/*!*/ eToResult) {
Contract.Requires(eToResult != null);
Contract.Requires(e != null);
Contract.Ensures(Contract.Result() != null);
Element/*!*/ result = e;
foreach (G.KeyValuePair*//*!*/> entry in eToResult.GetSourceToResult()) {
IVariable/*!*/ sourceName = entry.Key;
Contract.Assert(sourceName != null);
ISet/**//*!*/>/*!*/ emptyDictionary1 = new G.Dictionary*//*!*/>();
private static readonly G.Dictionary/*!*/ emptyDictionary2 = new G.Dictionary();
[ContractInvariantMethod]
void ObjectInvariant() {
Contract.Invariant(Map != null);
Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary1) && Contract.ForAll(emptyDictionary1.Values, set =>/*cce.NonNullElements(set)*/set != null));
Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary2));
Contract.Invariant(indexMap != null);
Contract.Invariant(reverseIndexMap != null);
}
public ISet/**//*?*/ GetResultNames(IVariable/*!*/ srcname) {
//Contract.Requires(srcname != null);
ArraySet a = new ArraySet();
a.Add(srcname);
return a;
}
public IVariable/*?*/ GetSourceName(IVariable/*!*/ resname) {
//Contract.Requires(resname != null);
return resname;
}
//TODO: uncomment when works in compiler
//public G.IEnumerable*/!>> GetSourceToResult()
public IEnumerable/*!*/ GetSourceToResult() {
Contract.Ensures(Contract.Result() != null);
return emptyDictionary1;
}
//public G.IEnumerable> GetResultToSource()
public IEnumerable/*!*/ GetResultToSource() {
Contract.Ensures(Contract.Result() != null);
return emptyDictionary2;
}
private IdentityCombineNameMap() {
}
}
#region Support for MultiLattice to uniquely number every subclass of Lattice
private static Hashtable/**//*!*/ indexMap = new Hashtable();
private static Hashtable/**//*!*/ reverseIndexMap = new Hashtable();
private static int globalCount = 0;
protected virtual object/*!*/ UniqueId {
get {
Contract.Ensures(Contract.Result