5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2011 Alexander Chebaturkin
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections.Generic;
32 using Mono.CodeContracts.Static.AST;
33 using Mono.CodeContracts.Static.DataStructures;
35 namespace Mono.CodeContracts.Static.ControlFlow {
36 struct APC : IEquatable<APC> {
37 public static readonly APC Dummy = new APC (null, 0, null);
39 public readonly CFGBlock Block;
40 public readonly int Index;
41 public readonly Sequence<Edge<CFGBlock, EdgeTag>> SubroutineContext;
43 public APC (CFGBlock block, int index, Sequence<Edge<CFGBlock, EdgeTag>> subroutineContext)
47 this.SubroutineContext = subroutineContext;
50 public IEnumerable<APC> Successors
52 get { return this.Block.Subroutine.Successors (this); }
55 public bool InsideContract
59 Subroutine sub = this.Block.Subroutine;
60 return sub.IsContract || sub.IsOldValue;
64 public bool InsideConstructor
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)
74 if (subroutine.IsMethod)
77 block = ctx.Head.From;
86 public bool InsideEnsuresInMethod
90 if (!this.Block.Subroutine.IsEnsuresOrOldValue || this.SubroutineContext == null)
92 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
93 if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
101 public bool InsideRequiresAtCall
105 if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
108 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
109 if (edge.Tag == EdgeTag.Entry)
111 if (edge.Tag.Is (EdgeTag.BeforeMask))
119 public bool InsideEnsuresAtCall
123 if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
126 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
127 if (edge.Tag == EdgeTag.Exit)
129 if (edge.Tag.Is (EdgeTag.BeforeMask))
137 public bool InsideInvariantOnExit
141 if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
143 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
144 if (edge.Tag == EdgeTag.Exit)
146 if (edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
154 public bool InsideInvariantInMethod
158 if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
161 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
162 if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry || edge.Tag.Is (EdgeTag.AfterMask))
170 public bool InsideInvariantAtCall
174 if (!this.Block.Subroutine.IsInvariant || this.SubroutineContext == null)
176 foreach (var edge in this.SubroutineContext.AsEnumerable ()) {
177 if (edge.Tag == EdgeTag.Exit || edge.Tag == EdgeTag.Entry)
179 if (edge.Tag.Is (EdgeTag.AfterMask))
187 public bool InsideOldManifestation
189 get { throw new NotImplementedException (); }
192 public bool InsideRequiresAtCallInsideContract
196 if (!this.Block.Subroutine.IsRequires || this.SubroutineContext == null)
198 for (Sequence<Edge<CFGBlock, EdgeTag>> list = this.SubroutineContext; list != null; list = list.Tail) {
199 if (list.Head.Tag == EdgeTag.Entry)
201 if (list.Head.Tag.Is (EdgeTag.BeforeMask)) {
202 Subroutine sub = list.Head.From.Subroutine;
203 return sub.IsEnsuresOrOldValue || sub.IsRequires || sub.IsInvariant;
206 throw new InvalidOperationException ("Should not happen");
210 #region IEquatable<APC> Members
211 public bool Equals (APC other)
213 return (this.Block == other.Block && this.Index == other.Index && this.SubroutineContext == other.SubroutineContext);
219 if (this.Index < this.Block.Count)
220 return new APC (this.Block, this.Index + 1, this.SubroutineContext);
225 public static APC ForEnd (CFGBlock block, Sequence<Edge<CFGBlock, EdgeTag>> subroutineContext)
227 return new APC (block, block.Count, subroutineContext);
230 public static APC ForStart (CFGBlock block, Sequence<Edge<CFGBlock, EdgeTag>> subroutineContext)
232 return new APC (block, 0, subroutineContext);
235 public APC LastInBlock ()
237 return ForEnd (this.Block, this.SubroutineContext);
240 public bool TryGetContainingMethod (out Method method)
242 Sequence<Edge<CFGBlock, EdgeTag>> list = this.SubroutineContext;
243 CFGBlock block = this.Block;
244 while (block != null) {
245 var mi = block.Subroutine as IMethodInfo;
252 block = list.Head.From;
257 method = default(Method);
261 static void ToString (StringBuilder sb, Sequence<Edge<CFGBlock, EdgeTag>> context)
263 bool wasFirst = false;
264 for (; context != null; context = context.Tail) {
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);
278 public override string ToString ()
280 var sb = new StringBuilder ();
282 sb.AppendFormat ("SR{2} {0},{1}", this.Block.Index, this.Index, this.Block.Subroutine.Id);
283 ToString (sb, this.SubroutineContext);
286 return sb.ToString ();