The base architecture for code-contracts analysis
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.ContractExtraction / HelperMethods.cs
1 // 
2 // HelperMethods.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 Mono.CodeContracts.Static.AST;
32
33 namespace Mono.CodeContracts.Static.ContractExtraction {
34         static class HelperMethods {
35                 public static Method IsMethodCall (Statement s)
36                 {
37                         if (s == null)
38                                 return null;
39
40                         var expressionStatement = s as ExpressionStatement;
41                         if (expressionStatement == null)
42                                 return null;
43
44                         var methodCall = expressionStatement.Expression as MethodCall;
45                         if (methodCall == null)
46                                 return null;
47
48                         var binding = methodCall.Callee as MemberBinding;
49                         if (binding == null)
50                                 return null;
51
52                         return binding.BoundMember as Method;
53                 }
54
55                 public static Local ExtractPreamble (Method method, ContractNodes contractNodes, Block contractInitializer, out Block postPreamble)
56                 {
57                         postPreamble = null;
58                         return null;
59                 }
60
61                 public static List<Statement> ExtractContractBlocks (List<Statement> blocks, int firstBlockIndex, int firstStmtIndex, int lastBlockIndex, int lastStmtIndex)
62                 {
63                         var result = new List<Statement> ();
64                         var firstBlock = (Block) blocks [firstBlockIndex];
65                         var block = new Block (new List<Statement> ());
66                         if (firstBlock != null) {
67                                 int cnt = firstBlockIndex == lastBlockIndex ? lastStmtIndex + 1 : firstBlock.Statements.Count;
68                                 for (int i = firstStmtIndex; i < cnt; i++) {
69                                         Statement stmt = firstBlock.Statements [i];
70                                         block.Statements.Add (stmt);
71                                         if (stmt != null)
72                                                 firstBlock.Statements [i] = null;
73                                 }
74                         }
75                         result.Add (block);
76                         int nextIndex = firstBlockIndex + 1;
77                         if (nextIndex > lastBlockIndex)
78                                 return result;
79                         Block newLastBlock = null;
80                         int lastFullBlockIndex = lastBlockIndex - 1;
81                         var lastBlock = (Block) blocks [lastBlockIndex];
82                         if (lastBlock != null && lastStmtIndex == lastBlock.Statements.Count - 1)
83                                 lastFullBlockIndex = lastBlockIndex;
84                         else {
85                                 newLastBlock = new Block (new List<Statement> ());
86                                 if (block.Statements != null && block.Statements.Count > 0) {
87                                         var branch = block.Statements [block.Statements.Count - 1] as Branch;
88                                         if (branch != null && branch.Target != null && branch.Target == lastBlock)
89                                                 branch.Target = newLastBlock;
90                                 }
91                         }
92
93                         for (; nextIndex < lastFullBlockIndex; ++nextIndex) {
94                                 var curBlock = (Block) blocks [nextIndex];
95                                 result.Add (curBlock);
96                                 if (curBlock != null) {
97                                         blocks [nextIndex] = null;
98                                         if (newLastBlock != null && curBlock.Statements != null && curBlock.Statements.Count > 0) {
99                                                 var branch = curBlock.Statements [curBlock.Statements.Count - 1] as Branch;
100                                                 if (branch != null && branch.Target != null && branch.Target == lastBlock)
101                                                         branch.Target = newLastBlock;
102                                         }
103                                 }
104                         }
105
106                         if (newLastBlock != null) {
107                                 for (int i = 0; i < lastStmtIndex + 1; i++) {
108                                         newLastBlock.Statements.Add (lastBlock.Statements [i]);
109                                         lastBlock.Statements [i] = null;
110                                 }
111
112                                 result.Add (newLastBlock);
113                         }
114                         return result;
115                 }
116
117                 public static bool IsCompilerGenerated (TypeNode type)
118                 {
119                         throw new NotImplementedException ();
120                 }
121
122                 public static int FindNextRealStatement (List<Statement> stmts, int beginIndex)
123                 {
124                         if (stmts == null || stmts.Count <= beginIndex)
125                                 return -1;
126                         int index = beginIndex;
127                         while (index < stmts.Count && (stmts [index] == null || stmts [index].NodeType == NodeType.Nop))
128                                 ++index;
129                         return index;
130                 }
131
132                 public static bool IsReferenceAsVisibleAs (Member member, Member asThisMember)
133                 {
134                         var type = member as TypeNode;
135                         if (type != null)
136                                 return IsTypeAsVisibleAs (type, asThisMember);
137                         var method = member as Method;
138                         Member member1;
139                         if (method != null) {
140                                 if (method.HasGenericParameters)
141                                         throw new NotImplementedException ();
142                                 member1 = method;
143                         } else
144                                 member1 = Unspecialize (member);
145
146                         return IsDefinitionAsVisibleAs (member1, asThisMember);
147                 }
148
149                 private static bool IsDefinitionAsVisibleAs (this Member member, Member asThisMember)
150                 {
151                         Module memberModule = member.Module;
152                         Module asThisMemberModule = asThisMember.Module;
153
154                         for (Member mbr = member; mbr != null; mbr = mbr.DeclaringType) {
155                                 if (!mbr.IsPublic) {
156                                         bool visible = false;
157                                         for (Member mbr1 = asThisMember; mbr1 != null; mbr1 = mbr1.DeclaringType) {
158                                                 if (mbr1.IsAssembly) {
159                                                         if ((mbr1.IsPrivate || mbr1.IsAssembly) && memberModule == asThisMemberModule)
160                                                                 visible = true;
161                                                 } else if (mbr1.IsFamily) {
162                                                         if (mbr.IsPrivate) {
163                                                                 if (IsInsideOf (mbr, mbr1) || IsInsideSubclass (mbr, mbr1.DeclaringType))
164                                                                         visible = true;
165                                                         } else if (mbr.IsFamily && (mbr.DeclaringType == mbr1.DeclaringType || IsSubclassOf (mbr.DeclaringType, mbr1.DeclaringType)))
166                                                                 visible = true;
167                                                 } else if (mbr1.IsFamilyOrAssembly) {
168                                                         if (mbr.IsPrivate) {
169                                                                 if (memberModule == asThisMemberModule || IsInsideSubclass (mbr, mbr1.DeclaringType))
170                                                                         visible = true;
171                                                         } else if (mbr.IsAssembly) {
172                                                                 if (memberModule == asThisMemberModule)
173                                                                         visible = true;
174                                                         } else if (mbr.IsFamily) {
175                                                                 if (IsSubclassOf (mbr.DeclaringType, mbr1.DeclaringType))
176                                                                         visible = true;
177                                                         } else if (mbr.IsFamilyOrAssembly && memberModule == asThisMemberModule && IsSubclassOf (mbr.DeclaringType, mbr1.DeclaringType))
178                                                                 visible = true;
179                                                 } else if (mbr1.IsPrivate && mbr.IsPrivate && IsInsideOf (mbr, mbr1.DeclaringType))
180                                                         visible = true;
181                                         }
182                                         if (!visible)
183                                                 return false;
184                                 }
185                         }
186                         return true;
187                 }
188
189                 private static bool IsSubclassOf (this TypeNode thisType, TypeNode thatType)
190                 {
191                         if (thatType == null)
192                                 return false;
193                         return thisType.IsAssignableTo (thatType);
194                 }
195
196                 private static bool IsInsideSubclass (this Member member, Member thatValue)
197                 {
198                         var targetType = thatValue as TypeNode;
199                         if (targetType == null)
200                                 return false;
201
202                         for (TypeNode declaringType = member.DeclaringType; declaringType != null; declaringType = declaringType.DeclaringType) {
203                                 if (declaringType.IsAssignableTo (targetType))
204                                         return true;
205                         }
206                         return false;
207                 }
208
209                 private static bool IsInsideOf (this Member thisValue, Member thatValue)
210                 {
211                         var typeNode = thatValue as TypeNode;
212                         if (typeNode == null)
213                                 return false;
214                         for (TypeNode declaringType = thisValue.DeclaringType; declaringType != null; declaringType = declaringType.DeclaringType) {
215                                 if (declaringType == typeNode)
216                                         return true;
217                         }
218                         return false;
219                 }
220
221                 private static Member Unspecialize (Member member)
222                 {
223                         return member;
224                 }
225
226                 private static bool IsTypeAsVisibleAs (this TypeNode type, Member asThisMember)
227                 {
228                         if (type == null)
229                                 return true;
230
231                         switch (type.NodeType) {
232                         case NodeType.Reference:
233                                 return ((Reference) type).ElementType.IsTypeAsVisibleAs (asThisMember);
234                         default:
235                                 if (type.HasGenericParameters)
236                                         throw new NotImplementedException ();
237
238                                 return IsDefinitionAsVisibleAs (type, asThisMember);
239                         }
240                 }
241
242                 public static bool IsVisibleFrom (this TypeNode type, TypeNode from)
243                 {
244                         TypeNode declaringType = type.DeclaringType;
245                         if (declaringType != null) {
246                                 if (IsContainedIn (from, declaringType) || IsInheritedFrom (from, type))
247                                         return true;
248                                 if (type.IsNestedFamily)
249                                         return IsInheritedFrom (from, declaringType);
250                                 if (type.IsNestedPublic)
251                                         return IsVisibleFrom (declaringType, from);
252                                 if (type.IsNestedInternal) {
253                                         if (IsInheritedFrom (from, declaringType))
254                                                 return true;
255                                         if (declaringType.Module == from.Module)
256                                                 return IsVisibleFrom (declaringType, from);
257
258                                         return false;
259                                 }
260                                 if (type.IsNestedFamilyAndAssembly)
261                                         return from.Module == declaringType.Module && IsInheritedFrom (from, declaringType);
262                                 if ((type.IsAssembly || type.IsNestedAssembly) && declaringType.Module == from.Module)
263                                         return IsVisibleFrom (declaringType, from);
264
265                                 return false;
266                         }
267
268                         return type.Module == from.Module || type.IsPublic;
269                 }
270
271                 public static bool IsVisibleFrom (this Member member, TypeNode from)
272                 {
273                         var type = member as TypeNode;
274                         if (type != null)
275                                 return type.IsVisibleFrom (from);
276
277                         TypeNode declaringType = member.DeclaringType;
278                         if (from.IsContainedIn (declaringType))
279                                 return true;
280                         if (member.IsPublic)
281                                 return declaringType.IsVisibleFrom (from);
282                         if (member.IsFamily)
283                                 return from.IsInheritedFrom (declaringType);
284                         if (member.IsFamilyAndAssembly)
285                                 return from.Module == declaringType.Module && from.IsInheritedFrom (declaringType);
286                         if (member.IsFamilyOrAssembly) {
287                                 if (from.IsInheritedFrom (declaringType))
288                                         return true;
289                                 if (from.Module == declaringType.Module)
290                                         return declaringType.IsVisibleFrom (from);
291
292                                 return false;
293                         }
294
295                         return member.IsAssembly && declaringType.Module == from.Module && declaringType.IsVisibleFrom (from);
296                 }
297
298                 public static bool IsInheritedFrom (this TypeNode type, TypeNode from)
299                 {
300                         TypeNode baseClass;
301                         if (type.HasBaseClass (out baseClass)) {
302                                 if (baseClass == from || baseClass.IsInheritedFrom (from))
303                                         return true;
304                         }
305
306                         return false;
307                 }
308
309                 private static bool HasBaseClass (this TypeNode type, out TypeNode baseClass)
310                 {
311                         var clazz = type as Class;
312                         if (clazz != null && clazz.BaseType != null) {
313                                 baseClass = clazz.BaseType;
314                                 return true;
315                         }
316
317                         baseClass = default(TypeNode);
318                         return false;
319                 }
320
321                 public static bool IsContainedIn (this TypeNode inner, TypeNode outer)
322                 {
323                         if (inner == outer)
324                                 return true;
325
326                         if (inner.DeclaringType != null)
327                                 return inner.DeclaringType.IsContainedIn (outer);
328
329                         return false;
330                 }
331         }
332 }