Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.Analysis.Numerical / Analysis.ConstantEvaluator.cs
1 // 
2 // Analysis.ConstantEvaluator.cs
3 // 
4 // Authors:
5 //      Alexander Chebaturkin (chebaturkin@gmail.com)
6 // 
7 // Copyright (C) 2012 Alexander Chebaturkin
8 // 
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //  
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30
31 using Mono.CodeContracts.Static.AST;
32 using Mono.CodeContracts.Static.ControlFlow;
33 using Mono.CodeContracts.Static.DataStructures;
34 using Mono.CodeContracts.Static.Lattices;
35 using Mono.CodeContracts.Static.Providers;
36 using Mono.CodeContracts.Static.Proving;
37
38 namespace Mono.CodeContracts.Static.Analysis.Numerical {
39         static partial class AnalysisFacade {
40                 static partial class Bind<TVar, TExpr>
41                         where TExpr : IEquatable<TExpr>
42                         where TVar : IEquatable<TVar> {
43                         class ConstantEvaluator {
44                                 readonly IExpressionContextProvider<TExpr, TVar> context_provider;
45                                 readonly IMetaDataProvider meta_data_provider;
46
47                                 public ConstantEvaluator (IExpressionContextProvider<TExpr, TVar> contextProvider,
48                                                           IMetaDataProvider metaDataProvider)
49                                 {
50                                         context_provider = contextProvider;
51                                         meta_data_provider = metaDataProvider;
52                                 }
53
54                                 public bool TryEvaluateToConstant (APC pc, TVar dest, BinaryOperator op,
55                                                                    BoxedExpression left, BoxedExpression right,
56                                                                    out long value)
57                                 {
58                                         var type =
59                                                 context_provider.ValueContext.GetType (
60                                                         context_provider.MethodContext.CFG.Post (pc), dest);
61                                         long l;
62                                         long r;
63
64                                         if (type.IsNormal () && TryEvaluateToConstant (pc, left, out l) &&
65                                             TryEvaluateToConstant (pc, right, out r))
66                                                 return TryEvaluate (type.Value, op, l, r, out value);
67
68                                         return false.Without (out value);
69                                 }
70
71                                 bool TryEvaluate (TypeNode type, BinaryOperator op, long l, long r, out long value)
72                                 {
73                                         if (TryEvaluateIndependent (op, l, r, out value))
74                                                 return true;
75
76                                         if (meta_data_provider.System_Int32.Equals (type))
77                                                 return TryEvaluateInt32 (op, (int) l, (int) r, out value);
78
79                                         return false.Without (out value);
80                                 }
81
82                                 static bool TryEvaluateInt32 (BinaryOperator op, int l, int r, out long value)
83                                 {
84                                         int result;
85                                         if (EvaluateArithmeticWithOverflow.TryBinary (op.ToExpressionOperator (), l, r,
86                                                                                       out result))
87                                                 return true.With (result, out value);
88
89                                         return false.Without (out value);
90                                 }
91
92                                 bool TryEvaluateIndependent (BinaryOperator op, long l, long r, out long result)
93                                 {
94                                         switch (op) {
95                                         case BinaryOperator.And:
96                                                 return true.With (l & r, out result);
97                                         case BinaryOperator.Ceq:
98                                                 return true.With (ToInt (l == r), out result);
99                                         case BinaryOperator.Cne_Un:
100                                                 return true.With (ToInt (l != r), out result);
101                                         case BinaryOperator.Cge:
102                                                 return true.With (ToInt (l >= r), out result);
103                                         case BinaryOperator.Cgt:
104                                                 return true.With (ToInt (l > r), out result);
105                                         case BinaryOperator.Cle:
106                                                 return true.With (ToInt (l <= r), out result);
107                                         case BinaryOperator.Clt:
108                                                 return true.With (ToInt (l < r), out result);
109                                         case BinaryOperator.LogicalAnd:
110                                                 return true.With (ToInt (l != 0 && r != 0), out result);
111                                         case BinaryOperator.LogicalOr:
112                                                 return true.With (ToInt (l != 0 || r != 0), out result);
113                                         case BinaryOperator.Or:
114                                                 return true.With (l | r, out result);
115                                         case BinaryOperator.Xor:
116                                                 return true.With (l ^ r, out result);
117                                         default:
118                                                 return false.Without (out result);
119                                         }
120                                 }
121
122                                 static long ToInt (bool value)
123                                 {
124                                         return value ? 1 : 0;
125                                 }
126
127                                 static bool TryEvaluateToConstant (APC pc, BoxedExpression e, out long result)
128                                 {
129                                         int res;
130                                         if (e.IsConstantIntOrNull (out res))
131                                                 return true.With (res, out result);
132
133                                         long argValue;
134                                         if (e.IsUnary && TryEvaluateToConstant (pc, e.UnaryArgument, out argValue)) {
135                                                 switch (e.UnaryOperator) {
136                                                 case UnaryOperator.Neg:
137                                                         return true.With (-argValue, out result);
138                                                 case UnaryOperator.Not:
139                                                         return true.With (argValue != 0 ? 0L : 1L, out result);
140                                                 default:
141                                                         throw new ArgumentOutOfRangeException ();
142                                                 }
143                                         }
144
145                                         return false.Without (out result);
146                                 }
147                         }
148                  }
149         }
150 }