Moved back to Cecil version 0.6.*
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Rewrite / TransformContractsVisitor.cs
1 //\r
2 // TransformContractsVisitor.cs\r
3 //\r
4 // Authors:\r
5 //      Chris Bacon (chrisbacon76@gmail.com)\r
6 //\r
7 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)\r
8 //\r
9 // Permission is hereby granted, free of charge, to any person obtaining\r
10 // a copy of this software and associated documentation files (the\r
11 // "Software"), to deal in the Software without restriction, including\r
12 // without limitation the rights to use, copy, modify, merge, publish,\r
13 // distribute, sublicense, and/or sell copies of the Software, and to\r
14 // permit persons to whom the Software is furnished to do so, subject to\r
15 // the following conditions:\r
16 // \r
17 // The above copyright notice and this permission notice shall be\r
18 // included in all copies or substantial portions of the Software.\r
19 // \r
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
27 //\r
28 \r
29 using System;\r
30 using System.Collections.Generic;\r
31 using System.Linq;\r
32 using System.Text;\r
33 using Mono.CodeContracts.Rewrite;\r
34 using Mono.CodeContracts.Rewrite.Ast;\r
35 using System.Diagnostics.Contracts;\r
36 using Mono.Cecil;\r
37 using Mono.CodeContracts.Rewrite.AstVisitors;\r
38 using Mono.Cecil.Cil;\r
39 \r
40 namespace Mono.CodeContracts.Rewrite {\r
41         class TransformContractsVisitor : ExprVisitor {\r
42 \r
43                 public TransformContractsVisitor (ModuleDefinition module, MethodDefinition method, Dictionary<Expr, Instruction> instructionLookup, ContractsRuntime contractsRuntime)\r
44                 {\r
45                         //this.module = method.Module;\r
46                         this.instructionLookup = instructionLookup;\r
47                         this.contractsRuntime = contractsRuntime;\r
48                         this.methodInfo = new MethodInfo (module, method);\r
49                 }\r
50 \r
51                 //private ModuleDefinition module;\r
52                 private Dictionary<Expr, Instruction> instructionLookup;\r
53                 private ContractsRuntime contractsRuntime;\r
54                 private MethodInfo methodInfo;\r
55 \r
56                 private List<ContractRequiresInfo> contractRequiresInfo = new List<ContractRequiresInfo> ();\r
57 \r
58                 public IEnumerable<ContractRequiresInfo> ContractRequiresInfo {\r
59                         get { return this.contractRequiresInfo; }\r
60                 }\r
61 \r
62                 protected override Expr VisitCall (ExprCall e)\r
63                 {\r
64                         var call = (ExprCall)base.VisitCall (e);\r
65 \r
66                         var method = e.Method;\r
67                         if (method.DeclaringType.FullName == "System.Diagnostics.Contracts.Contract") {\r
68                                 switch (method.Name) {\r
69                                 case "Requires":\r
70                                         if (!method.HasGenericParameters) {\r
71                                                 switch (method.Parameters.Count) {\r
72                                                 case 1:\r
73                                                         return this.ProcessRequires1 (call);\r
74                                                 case 2:\r
75                                                         return this.ProcessRequires2 (call);\r
76                                                 default:\r
77                                                         throw new NotSupportedException ("Invalid number of parameters to Contract.Requires()");\r
78                                                 }\r
79                                         } else {\r
80                                                 goto default;\r
81                                         }\r
82                                 default:\r
83                                         throw new NotSupportedException ("Cannot handle Contract." + e.Method.Name + "()");\r
84                                 }\r
85                         }\r
86 \r
87                         return call;\r
88                 }\r
89 \r
90                 private string GetConditionString (Expr e)\r
91                 {\r
92                         var vSource = new SourcePositionVisitor (this.instructionLookup);\r
93                         vSource.Visit (e);\r
94                         var extractor = new ConditionTextExtractor (vSource.SourceCodeFileName, vSource.StartPosition, vSource.EndPosition);\r
95                         return extractor.GetConditionText ();\r
96                 }\r
97 \r
98                 private Expr ProcessRequires1 (ExprCall e)\r
99                 {\r
100                         MethodDefinition mRequires = this.contractsRuntime.GetRequires ();\r
101                         Expr conditionExpr = e.Parameters.First ();\r
102                         Expr nullArgExpr = new ExprLoadConstant (this.methodInfo, null);\r
103                         string conditionText = this.GetConditionString (e);\r
104                         Expr conditionStringExpr = new ExprLoadConstant (this.methodInfo, conditionText);\r
105                         var call = new ExprCall (this.methodInfo, mRequires, new Expr [] { conditionExpr, nullArgExpr, conditionStringExpr });\r
106 \r
107                         this.contractRequiresInfo.Add (new ContractRequiresInfo (e, call));\r
108 \r
109                         return call;\r
110                 }\r
111 \r
112                 private Expr ProcessRequires2 (ExprCall e)\r
113                 {\r
114                         MethodDefinition mRequires = this.contractsRuntime.GetRequires ();\r
115                         Expr conditionExpr = e.Parameters.First ();\r
116                         Expr msgExpr = e.Parameters.ElementAt (1);\r
117                         string conditionText = this.GetConditionString (e);\r
118                         Expr conditionStringExpr = new ExprLoadConstant (this.methodInfo, conditionText);\r
119                         var call = new ExprCall (this.methodInfo, mRequires, new Expr [] { conditionExpr, msgExpr, conditionStringExpr });\r
120 \r
121                         this.contractRequiresInfo.Add (new ContractRequiresInfo (e, call));\r
122 \r
123                         return call;\r
124                 }\r
125 \r
126         }\r
127 }\r