Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

154 lines
5.4 KiB
C#

//
// ExpressionAssumeDecoder.cs
//
// Authors:
// Alexander Chebaturkin (chebaturkin@gmail.com)
//
// Copyright (C) 2011 Alexander Chebaturkin
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using Mono.CodeContracts.Static.AST;
using Mono.CodeContracts.Static.AST.Visitors;
using Mono.CodeContracts.Static.DataStructures;
namespace Mono.CodeContracts.Static.Analysis.NonNull {
struct ExpressionAssumeDecoder<E, V>
: ISymbolicExpressionVisitor<E, E, V, Pair<bool, NonNullDomain<V>>, NonNullDomain<V>>
where V : IEquatable<V>
where E : IEquatable<E> {
private readonly IExpressionContextProvider<E, V> context_provider;
public ExpressionAssumeDecoder (IExpressionContextProvider<E, V> contextProvider)
{
this.context_provider = contextProvider;
}
#region ISymbolicExpressionVisitor<E,E,V,Pair<bool,Domain<E,V>>,Domain<E,V>> Members
public NonNullDomain<V> Binary (E pc, BinaryOperator op, V dest, E operand1, E operand2, Pair<bool, NonNullDomain<V>> data)
{
IExpressionContext<E, V> exprCtx = this.context_provider.ExpressionContext;
switch (op) {
case BinaryOperator.Ceq:
case BinaryOperator.Cobjeq:
if (data.Value.IsNull (exprCtx.Unrefine (operand2)) || exprCtx.IsZero (operand2)
|| data.Value.IsNull (exprCtx.Unrefine (operand1)) || exprCtx.IsZero (operand1))
return Recurse (new Pair<bool, NonNullDomain<V>> (!data.Key, data.Value), operand1);
if (data.Value.IsNonNull (exprCtx.Unrefine (operand1)) || data.Value.IsNonNull (exprCtx.Unrefine (operand2)))
return Analysis<E, V>.AssumeNonNull (exprCtx.Unrefine (operand2), data.Value);
return data.Value;
case BinaryOperator.Cne_Un:
if (data.Value.IsNull (exprCtx.Unrefine (operand2)) || exprCtx.IsZero (operand2)
|| data.Value.IsNull (exprCtx.Unrefine (operand1)) || exprCtx.IsZero (operand1))
return Recurse (data, operand1);
return data.Value;
default:
return data.Value;
}
}
public NonNullDomain<V> Isinst (E pc, TypeNode type, V dest, E obj, Pair<bool, NonNullDomain<V>> data)
{
if (data.Key)
return Recurse (new Pair<bool, NonNullDomain<V>> (true, Analysis<E, V>.AssumeNonNull (dest, data.Value)), obj);
return data.Value;
}
public NonNullDomain<V> LoadNull (E pc, V dest, Pair<bool, NonNullDomain<V>> data)
{
if (data.Key)
return NonNullDomain<V>.BottomValue;
return data.Value;
}
public NonNullDomain<V> LoadConst (E pc, TypeNode type, object constant, V dest, Pair<bool, NonNullDomain<V>> data)
{
if (constant is string)
return data.Value;
var convertible = constant as IConvertible;
bool isZero = false;
if (convertible != null) {
try {
isZero = convertible.ToInt32 (null) == 0;
} catch {
return data.Value;
}
}
if (data.Key && isZero || !data.Key && !isZero)
return NonNullDomain<V>.BottomValue;
return data.Value;
}
public NonNullDomain<V> Sizeof (E pc, TypeNode type, V dest, Pair<bool, NonNullDomain<V>> data)
{
return data.Value;
}
public NonNullDomain<V> Unary (E pc, UnaryOperator op, bool unsigned, V dest, E source, Pair<bool, NonNullDomain<V>> data)
{
switch (op) {
case UnaryOperator.Conv_i:
case UnaryOperator.Conv_i1:
case UnaryOperator.Conv_i2:
case UnaryOperator.Conv_i4:
case UnaryOperator.Conv_i8:
case UnaryOperator.Conv_u:
case UnaryOperator.Conv_u1:
case UnaryOperator.Conv_u2:
case UnaryOperator.Conv_u4:
case UnaryOperator.Conv_u8:
return Recurse (data, source);
case UnaryOperator.Neg:
return Recurse (data, source);
case UnaryOperator.Not:
return Recurse (new Pair<bool, NonNullDomain<V>> (!data.Key, data.Value), source);
default:
return data.Value;
}
}
public NonNullDomain<V> SymbolicConstant (E orig, V variable, Pair<bool, NonNullDomain<V>> data)
{
if (data.Key) {
return !this.context_provider.ExpressionContext.IsZero (orig)
? NonNullDomain<V>.BottomValue
: Analysis<E, V>.AssumeNonNull (variable, data.Value);
}
if (data.Value.NonNulls.Contains (variable))
return NonNullDomain<V>.BottomValue;
return Analysis<E, V>.AssumeNull (variable, data.Value);
}
#endregion
private NonNullDomain<V> Recurse (Pair<bool, NonNullDomain<V>> pair, E expr)
{
return this.context_provider.ExpressionContext.Decode<Pair<bool, NonNullDomain<V>>, NonNullDomain<V>, ExpressionAssumeDecoder<E, V>> (expr, this, pair);
}
}
}