Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.ControlFlow / APC.cs
1 // 
2 // APC.cs
3 // 
4 // Authors:
5 //      Alexander Chebaturkin (chebaturkin@gmail.com)
6 // 
7 // Copyright (C) 2011 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 using System.Collections.Generic;
31 using System.Text;
32 using Mono.CodeContracts.Static.AST;
33 using Mono.CodeContracts.Static.DataStructures;
34
35 namespace Mono.CodeContracts.Static.ControlFlow {
36         struct APC : IEquatable<APC> {
37                 public static readonly APC Dummy = new APC (null, 0, null);
38
39                 public readonly CFGBlock Block;
40                 public readonly int Index;
41                 public readonly Sequence<Edge<CFGBlock, EdgeTag>> SubroutineContext;
42
43                 public APC (CFGBlock block, int index, Sequence<Edge<CFGBlock, EdgeTag>> subroutineContext)
44                 {
45                         this.Block = block;
46                         this.Index = index;
47                         this.SubroutineContext = subroutineContext;
48                 }
49
50                 public IEnumerable<APC> Successors
51                 {
52                         get { return this.Block.Subroutine.Successors (this); }
53                 }
54
55                 public bool InsideContract
56                 {
57                         get
58                         {
59                                 Subroutine sub = this.Block.Subroutine;
60                                 return sub.IsContract || sub.IsOldValue;
61                         }
62                 }
63
64                 public bool InsideConstructor
65                 {
66                         get
67                         {
68                                 Sequence<Edge<CFGBlock, EdgeTag>> ctx = this.SubroutineContext;
69                                 CFGBlock block = this.Block;
70                                 while (block != null) {
71                                         Subroutine subroutine = block.Subroutine;
72                                         if (subroutine.IsConstructor)
73                                                 return true;
74                                         if (subroutine.IsMethod)
75                                                 return false;
76                                         if (ctx != null) {
77                                                 block = ctx.Head.From;
78                                                 ctx = ctx.Tail;
79                                         } else
80                                                 block = null;
81                                 }
82                                 return false;
83                         }
84                 }
85
86                 public bool InsideEnsuresInMethod
87                 {
88                         get
89                         {
90                                 if (!this.Block.Subroutine.IsEnsuresOrOldValue || this.SubroutineContext == null)
91                                         return false;
92                                 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
93                                         if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
94                                                 return true;
95                                 }
96
97                                 return false;
98                         }
99                 }
100
101                 public bool InsideRequiresAtCall
102                 {
103                         get
104                         {
105                                 if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
106                                         return false;
107
108                                 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
109                                         if (edge.Tag == EdgeTag.Entry)
110                                                 return false;
111                                         if (edge.Tag.Is (EdgeTag.BeforeMask))
112                                                 return true;
113                                 }
114
115                                 return false;
116                         }
117                 }
118
119                 public bool InsideEnsuresAtCall
120                 {
121                         get
122                         {
123                                 if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
124                                         return false;
125
126                                 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
127                                         if (edge.Tag == EdgeTag.Exit)
128                                                 return false;
129                                         if (edge.Tag.Is (EdgeTag.BeforeMask))
130                                                 return true;
131                                 }
132
133                                 return false;
134                         }
135                 }
136
137                 public bool InsideInvariantOnExit
138                 {
139                         get
140                         {
141                                 if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
142                                         return false;
143                                 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
144                                         if (edge.Tag == EdgeTag.Exit)
145                                                 return true;
146                                         if (edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
147                                                 return false;
148                                 }
149
150                                 return false;
151                         }
152                 }
153
154                 public bool InsideInvariantInMethod
155                 {
156                         get
157                         {
158                                 if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
159                                         return false;
160
161                                 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
162                                         if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
163                                                 return true;
164                                 }
165
166                                 return false;
167                         }
168                 }
169
170                 public bool InsideInvariantAtCall
171                 {
172                         get
173                         {
174                                 if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
175                                         return false;
176                                 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
177                                         if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry)
178                                                 return false;
179                                         if (edge.Tag.Is (EdgeTag.AfterMask))
180                                                 return true;
181                                 }
182
183                                 return false;
184                         }
185                 }
186
187                 public bool InsideOldManifestation
188                 {
189                         get { throw new NotImplementedException (); }
190                 }
191
192                 public bool InsideRequiresAtCallInsideContract
193                 {
194                         get
195                         {
196                                 if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
197                                         return false;
198                                 for (Sequence<Edge<CFGBlock, EdgeTag>> list = this.SubroutineContext; list != null; list = list.Tail) {
199                                         if (list.Head.Tag == EdgeTag.Entry)
200                                                 return false;
201                                         if (list.Head.Tag.Is (EdgeTag.BeforeMask)) {
202                                                 Subroutine sub = list.Head.From.Subroutine;
203                                                 return sub.IsEnsuresOrOldValue || sub.IsRequires || sub.IsInvariant;
204                                         }
205                                 }
206                                 throw new InvalidOperationException ("Should not happen");
207                         }
208                 }
209
210                 #region IEquatable<APC> Members
211                 public bool Equals (APC other)
212                 {
213                         return (this.Block == other.Block && this.Index == other.Index && this.SubroutineContext == other.SubroutineContext);
214                 }
215                 #endregion
216
217                 public APC Next ()
218                 {
219                         if (this.Index < this.Block.Count)
220                                 return new APC (this.Block, this.Index + 1, this.SubroutineContext);
221
222                         return this;
223                 }
224
225                 public static APC ForEnd (CFGBlock block, Sequence<Edge<CFGBlock, EdgeTag>> subroutineContext)
226                 {
227                         return new APC (block, block.Count, subroutineContext);
228                 }
229
230                 public static APC ForStart (CFGBlock block, Sequence<Edge<CFGBlock, EdgeTag>> subroutineContext)
231                 {
232                         return new APC (block, 0, subroutineContext);
233                 }
234
235                 public APC LastInBlock ()
236                 {
237                         return ForEnd (this.Block, this.SubroutineContext);
238                 }
239
240                 public bool TryGetContainingMethod (out Method method)
241                 {
242                         Sequence<Edge<CFGBlock, EdgeTag>> list = this.SubroutineContext;
243                         CFGBlock block = this.Block;
244                         while (block != null) {
245                                 var mi = block.Subroutine as IMethodInfo;
246                                 if (mi != null) {
247                                         method = mi.Method;
248                                         return true;
249                                 }
250
251                                 if (list != null) {
252                                         block = list.Head.From;
253                                         list = list.Tail;
254                                 } else
255                                         block = null;
256                         }
257                         method = default(Method);
258                         return false;
259                 }
260
261                 static void ToString (StringBuilder sb, Sequence<Edge<CFGBlock, EdgeTag>> context)
262                 {
263                         bool wasFirst = false;
264                         for (; context != null; context = context.Tail) {
265                                 if (!wasFirst) {
266                                         sb.Append ("{");
267                                         wasFirst = true;
268                                 } else
269                                         sb.Append (",");
270                                 Edge<CFGBlock, EdgeTag> head = context.Head;
271                                 sb.AppendFormat ("(SR{2} {0},{1}) [{3}]", head.From.Index, head.To.Index, head.From.Subroutine.Id, head.Tag);
272                         }
273                         if (!wasFirst)
274                                 return;
275                         sb.Append ("}");
276                 }
277
278                 public override string ToString ()
279                 {
280                         var sb = new StringBuilder ();
281                         sb.Append ("[");
282                         sb.AppendFormat ("SR{2} {0},{1}", this.Block.Index, this.Index, this.Block.Subroutine.Id);
283                         ToString (sb, this.SubroutineContext);
284                         sb.Append ("]");
285
286                         return sb.ToString ();
287                 }
288         }
289 }