The base architecture for code-contracts analysis
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.AST / Method.cs
1 // 
2 // Method.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.Linq;
32 using Mono.Cecil;
33 using Mono.Cecil.Cil;
34 using Mono.Collections.Generic;
35
36 namespace Mono.CodeContracts.Static.AST {
37         class Method : Member, IEquatable<Method> {
38                 #region Delegates
39                 public delegate void MethodContractProvider (Method method);
40                 #endregion
41
42                 private readonly MethodDefinition definition;
43                 private Block block;
44                 private MethodContract contract;
45                 private MethodContractProvider method_contract_provider;
46                 private List<Parameter> parameters;
47                 private TypeNode returnType;
48                 private This thisParameter;
49
50                 public Method (MethodDefinition definition)
51                         : base (NodeType.Method)
52                 {
53                         this.definition = definition;
54                 }
55
56                 private Method (MethodDefinition definition, Block block) : base (NodeType.Method)
57                 {
58                         this.definition = definition;
59                         this.block = block;
60                 }
61
62                 public bool HasGenericParameters
63                 {
64                         get { return this.definition.HasGenericParameters; }
65                 }
66
67                 public MethodDefinition Definition
68                 {
69                         get { return this.definition; }
70                 }
71
72                 public override TypeNode DeclaringType
73                 {
74                         get { return TypeNode.Create (this.definition.DeclaringType); }
75                 }
76
77                 public override Module Module
78                 {
79                         get { return new Module (this.definition.Module); }
80                 }
81
82                 public Method OverriddenMethod
83                 {
84                         get
85                         {
86                                 if (!this.definition.HasOverrides)
87                                         return null;
88                                 return ParseMethodDefinition (this.definition.Overrides [0].Resolve ());
89                         }
90                 }
91
92                 public Block Body
93                 {
94                         get
95                         {
96                                 if (this.block == null)
97                                         this.block = ParseMethodBlock (this.definition);
98                                 return this.block;
99                         }
100                         set { this.block = value; }
101                 }
102
103                 public MethodContract MethodContract
104                 {
105                         get
106                         {
107                                 if (this.contract == null && ContractProvider != null) {
108                                         MethodContractProvider provider = ContractProvider;
109                                         ContractProvider = null;
110                                         provider (this);
111                                 }
112                                 return this.contract;
113                         }
114                         set
115                         {
116                                 this.contract = value;
117                                 if (value != null)
118                                         this.contract.DeclaringMethod = this;
119                                 ContractProvider = null;
120                         }
121                 }
122
123                 public MethodContractProvider ContractProvider
124                 {
125                         get { return this.method_contract_provider; }
126                         set
127                         {
128                                 if (value == null) {
129                                         this.method_contract_provider = null;
130                                         return;
131                                 }
132
133                                 if (this.method_contract_provider != null)
134                                         this.method_contract_provider += value;
135                                 else
136                                         this.method_contract_provider = value;
137
138                                 this.contract = null;
139                         }
140                 }
141
142
143                 public bool IsFinal
144                 {
145                         get { return this.definition.IsFinal; }
146                 }
147
148                 public bool HasBody
149                 {
150                         get { return this.definition.HasBody; }
151                 }
152
153                 public override bool IsPrivate
154                 {
155                         get { return this.definition.IsPrivate; }
156                 }
157
158                 public override bool IsAssembly
159                 {
160                         get { return this.definition.IsAssembly; }
161                 }
162
163                 public override bool IsFamily
164                 {
165                         get { return this.definition.IsFamily; }
166                 }
167
168                 public override bool IsFamilyOrAssembly
169                 {
170                         get { return this.definition.IsFamilyOrAssembly; }
171                 }
172
173                 public override bool IsFamilyAndAssembly
174                 {
175                         get { return this.definition.IsFamilyAndAssembly; }
176                 }
177
178                 public override bool IsPublic
179                 {
180                         get { return this.definition.IsPublic; }
181                 }
182
183                 public bool IsProtected
184                 {
185                         get { return this.definition.IsFamily; }
186                 }
187
188                 public bool IsProtectedOrInternal
189                 {
190                         get { return this.definition.IsFamilyOrAssembly; }
191                 }
192
193                 public bool IsProtectedAndInternal
194                 {
195                         get { return this.definition.IsFamilyAndAssembly; }
196                 }
197
198                 public string Name
199                 {
200                         get { return this.definition.Name; }
201                 }
202
203                 public string FullName
204                 {
205                         get { return this.definition.FullName; }
206                 }
207
208                 public bool HasOverrides
209                 {
210                         get { return this.definition.HasOverrides; }
211                 }
212
213                 public bool IsVirtual
214                 {
215                         get { return this.definition.IsVirtual; }
216                 }
217
218                 public override bool IsStatic
219                 {
220                         get { return this.definition.IsStatic; }
221                 }
222
223                 public bool IsNewSlot
224                 {
225                         get { return this.definition.IsNewSlot; }
226                 }
227
228                 public bool IsAbstract
229                 {
230                         get { return this.definition.IsAbstract; }
231                 }
232
233                 public bool IsConstructor
234                 {
235                         get { return this.definition.IsConstructor; }
236                 }
237
238                 public List<Parameter> Parameters
239                 {
240                         get
241                         {
242                                 if (this.parameters == null)
243                                         this.parameters = this.definition.Parameters.Select (i => new Parameter (i)).ToList ();
244                                 return this.parameters;
245                         }
246                         set { this.parameters = value; }
247                 }
248
249                 public bool HasParameters
250                 {
251                         get { return Parameters != null && Parameters.Count > 0; }
252                 }
253
254                 public TypeNode ReturnType
255                 {
256                         get
257                         {
258                                 if (this.returnType == null)
259                                         this.returnType = TypeNode.Create (this.definition.ReturnType);
260                                 return this.returnType;
261                         }
262                         set { this.returnType = value; }
263                 }
264
265                 public bool IsSetter
266                 {
267                         get { return this.definition.IsSetter; }
268                 }
269
270                 public bool IsGetter
271                 {
272                         get { return this.definition.IsGetter; }
273                 }
274
275                 public This ThisParameter
276                 {
277                         get
278                         {
279                                 if (this.thisParameter == null && !IsStatic && DeclaringType != null)
280                                         ThisParameter = !DeclaringType.IsValueType ? new This (DeclaringType.SelfInstantiation ()) : new This (DeclaringType.SelfInstantiation ().GetReferenceType ());
281                                 return this.thisParameter;
282                         }
283                         private set
284                         {
285                                 this.thisParameter = value;
286                                 if (value != null)
287                                         this.thisParameter.DeclaringMethod = this;
288                         }
289                 }
290
291                 public Method DeclaringMethod { get; private set; }
292
293                 public List<TypeNode> GenericParameters
294                 {
295                         get
296                         {
297                                 Collection<GenericParameter> genericParameters = this.definition.GenericParameters;
298                                 if (genericParameters == null)
299                                         return null;
300                                 return genericParameters.Select (it => TypeNode.Create (it)).ToList ();
301                         }
302                 }
303
304                 public IList<Local> Locals
305                 {
306                         get
307                         {
308                                 Collection<VariableDefinition> variables = this.definition.Body.Variables;
309                                 if (variables == null)
310                                         return null;
311                                 return variables.Select (it => new Local (it)).ToList ();
312                         }
313                 }
314
315                 public bool IsCompilerGenerated
316                 {
317                         get { return this.definition.IsCompilerControlled; }
318                 }
319
320                 #region IEquatable<Method> Members
321                 public bool Equals (Method other)
322                 {
323                         return this.definition == other.definition;
324                 }
325                 #endregion
326
327                 public static Method ParseMethodDefinition (MethodDefinition methodDefinition)
328                 {
329                         Block methodBlock = ParseMethodBlock (methodDefinition);
330
331                         return new Method (methodDefinition, methodBlock);
332                 }
333
334                 private static Block ParseMethodBlock (MethodDefinition methodDefinition)
335                 {
336                         var bp = new BodyParser (methodDefinition);
337                         return new Block (bp.ParseBlocks ());
338                 }
339
340                 public override string ToString ()
341                 {
342                         return string.Format ("Method(Name: {0})", FullName);
343                 }
344         }
345 }