//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System.Diagnostics.Contracts; namespace Microsoft.AbstractInterpretationFramework { using System.Collections; using System.Diagnostics; //using System.Compiler.Analysis; public class NullnessLattice : MicroLattice { readonly INullnessFactory/*!*/ factory; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(factory != null); } public NullnessLattice(INullnessFactory/*!*/ factory) { Contract.Requires(factory != null); this.factory = factory; // base(); } enum Value { Bottom, NotNull, Null, MayBeNull } private class Elt : Element { public Value value; public Elt(Value v) { this.value = v; } [Pure] public override System.Collections.Generic.ICollection/*!*/ FreeVariables() { Contract.Ensures(cce.NonNullElements(Contract.Result>())); return cce.NonNull(new System.Collections.Generic.List()).AsReadOnly(); } public override Element/*!*/ Clone() { Contract.Ensures(Contract.Result() != null); return new Elt(this.value); } } public override Element/*!*/ Top { get { Contract.Ensures(Contract.Result() != null); return new Elt(Value.MayBeNull); } } public override Element/*!*/ Bottom { get { Contract.Ensures(Contract.Result() != null); return new Elt(Value.Bottom); } } public static Element/*!*/ Null { get { Contract.Ensures(Contract.Result() != null); return new Elt(Value.Null); } } public static Element/*!*/ NotNull { get { Contract.Ensures(Contract.Result() != null); return new Elt(Value.NotNull); } } public override bool IsTop(Element/*!*/ element) { //Contract.Requires(element != null); Elt e = (Elt)element; return e.value == Value.MayBeNull; } public override bool IsBottom(Element/*!*/ element) { //Contract.Requires(element != null); Elt e = (Elt)element; return e.value == Value.Bottom; } public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { //Contract.Requires(second != null); //Contract.Requires(first != null); Contract.Ensures(Contract.Result() != null); Elt a = (Elt)first; Elt b = (Elt)second; return (a.value == b.value) ? a : (Elt)Top; } public override Lattice.Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { //Contract.Requires(second != null); //Contract.Requires(first != null); Contract.Ensures(Contract.Result() != null); Elt a = (Elt)first; Elt b = (Elt)second; return (a.value == b.value) ? a : (Elt)Bottom; } public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { //Contract.Requires(second != null); //Contract.Requires(first != null); Contract.Ensures(Contract.Result() != null); return Join(first, second); } protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that { //Contract.Requires(first != null); //Contract.Requires(second != null); Elt a = (Elt)first; Elt b = (Elt)second; return a.value == b.value; } public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { //Contract.Requires(element != null); //Contract.Requires(var != null); Contract.Ensures(Contract.Result() != null); Elt e = (Elt)element; if (e.value == Value.NotNull) { return factory.Neq(var, factory.Null); } if (e.value == Value.Null) { return factory.Eq(var, factory.Null); } { Contract.Assert(false); throw new cce.UnreachableException(); } throw new System.Exception(); } public override IExpr GetFoldExpr(Element/*!*/ e) { //Contract.Requires(e != null); Elt elt = (Elt)e; if (elt.value == Value.Null) { return factory.Null; } else { // can't fold into an expression return null; } } public override bool Understands(IFunctionSymbol/*!*/ f, IList/**//*!*/ args) { //Contract.Requires(args != null); //Contract.Requires(f != null); if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { Contract.Assert(args.Count == 2); IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); // Look for "x OP null" or "null OP x" where OP is "==" or "!=". if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { return true; } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { return true; } } return false; } public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { //Contract.Requires(e != null); Contract.Ensures(Contract.Result() != null); IFunApp nary = e as IFunApp; if (nary != null) { bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { IList/**//*!*/ args = nary.Arguments; Contract.Assert(args != null); Contract.Assert(args.Count == 2); IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(args[1]); // Look for "x OP null" or "null OP x" where OP is "==" or "!=". IVariable var = null; if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) { var = (IVariable)arg0; } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) { var = (IVariable)arg1; } if (var != null) // found the pattern { return isEq ? Null : NotNull; } } } return Top; } } #if false public class NullnessMicroLattice : MicroLattice { public override MicroLatticeElement Top { get { return NullnessLatticeElement.Top; } } public override MicroLatticeElement Bottom { get { return NullnessLatticeElement.Bottom; } } public override MicroLatticeElement EvaluateExpression (Expr e, LookupValue lookup) { if (e is LiteralExpr && ((LiteralExpr)e).Val == null) { return NullnessLatticeElement.Null; } return Top; } public override MicroLatticeElement EvaluatePredicate (Expr e, LookupValue lookup) { NAryExpr nary = e as NAryExpr; if (nary != null && (nary.Fun.FunctionName.Equals("==") || nary.Fun.FunctionName.Equals("!="))) { Debug.Assert(nary.Args.Length == 2); Expr arg0 = nary.Args[0], arg1 = nary.Args[1]; Variable var = null; // Look for "x OP null" or "null OP x" where OP is "==" or "!=". if (arg0 is IdentifierExpr && arg1 is LiteralExpr && ((LiteralExpr)arg1).Val == null) { var = ((IdentifierExpr)arg0).Decl; } else if (arg1 is IdentifierExpr && arg0 is LiteralExpr && ((LiteralExpr)arg0).Val == null) { var = ((IdentifierExpr)arg1).Decl; } if (var != null) // found the pattern { return nary.Fun.FunctionName.Equals("==") ? NullnessLatticeElement.Null : NullnessLatticeElement.NotNull; } } return Top; } } #endif }