~ubuntu-branches/ubuntu/saucy/monodevelop/saucy-proposed

« back to all changes in this revision

Viewing changes to contrib/Mono.Cecil/Cecil.Decompiler/Cecil.Decompiler.Steps/RebuildForeachStatements.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2010-09-10 16:54:48 UTC
  • mfrom: (19.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100910165448-0rybfk25zd4o9431
Tags: 2.4+dfsg-2
* debian/patches/inject_Mono.Debugger.Soft_source.patch,
  debian/patches/use_system_Mono.Debugger.Soft.patch,
  debian/control:
  + Build against system Soft Debugger, since we now have a new
    enough Mono to match MonoDevelop's required API

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
using System.Linq;
 
2
 
 
3
using Cecil.Decompiler.Ast;
 
4
 
 
5
using Mono.Cecil.Cil;
 
6
 
 
7
namespace Cecil.Decompiler.Steps {
 
8
 
 
9
        internal class RebuildForeachStatements : Ast.BaseCodeVisitor, IDecompilationStep {
 
10
 
 
11
                public static readonly IDecompilationStep Instance = new RebuildForeachStatements ();
 
12
 
 
13
                DecompilationContext context;
 
14
 
 
15
                public override void VisitBlockStatement (BlockStatement node)
 
16
                {
 
17
                        ProcessBlock (node);
 
18
 
 
19
                        foreach (var statement in node.Statements)
 
20
                                Visit (statement);
 
21
                }
 
22
 
 
23
                void ProcessBlock (BlockStatement node)
 
24
                {
 
25
                        for (int i = 0; i < node.Statements.ToList ().Count - 1; i++) {
 
26
                                var matcher = new ForeachMatcher (node.Statements [i], node.Statements [i + 1]);
 
27
                                if (!matcher.Match ())
 
28
                                        continue;
 
29
                                context.RemoveVariable (matcher.Enumerator);
 
30
                                node.Statements.RemoveAt (i); // enumerator declaration/assignment
 
31
                                node.Statements.RemoveAt (i); // try
 
32
                                node.Statements.Insert (i, matcher.Foreach);
 
33
                                ProcessBlock (matcher.Foreach.Body);
 
34
                        }
 
35
                }
 
36
 
 
37
                public BlockStatement Process (DecompilationContext context, BlockStatement body)
 
38
                {
 
39
                        this.context = context;
 
40
                        Visit (body);
 
41
                        return body;
 
42
                }
 
43
 
 
44
                class ForeachMatcher {
 
45
 
 
46
                        enum State {
 
47
                                Begin,
 
48
                                WhileBody,
 
49
                                WhileCondition,
 
50
                                IfBody
 
51
                        }
 
52
 
 
53
                        ForEachStatement @foreach;
 
54
            VariableReference enumerator;
 
55
 
 
56
                        Expression source;
 
57
            BlockStatement while_body;
 
58
            VariableDefinition variable;
 
59
 
 
60
                        State state;
 
61
 
 
62
                        readonly Statement statement;
 
63
            readonly Statement next_statement;
 
64
 
 
65
                        public ForEachStatement Foreach {
 
66
                                get {
 
67
                                        @foreach = @foreach ?? new ForEachStatement (
 
68
                                                                new VariableDeclarationExpression (this.variable),
 
69
                                                                this.source,
 
70
                                                                this.while_body);
 
71
                                        return @foreach;
 
72
                                }
 
73
                        }
 
74
 
 
75
                        public VariableReference Enumerator {
 
76
                                get { return this.enumerator; }
 
77
                        }
 
78
 
 
79
                        public ForeachMatcher (Statement statement, Statement next_statement)
 
80
                        {
 
81
                                this.statement = statement;
 
82
                                this.next_statement = next_statement;
 
83
                        }
 
84
 
 
85
                        internal bool Match ()
 
86
                        {
 
87
                                state = State.Begin;
 
88
 
 
89
                                if (!VisitExpressionStatement (this.statement))
 
90
                                        return false;
 
91
 
 
92
                                if (!VisitTryStatement (this.next_statement))
 
93
                                        return false;
 
94
 
 
95
                                return true;
 
96
                        }
 
97
 
 
98
                        private bool VisitExpressionStatement (Statement node)
 
99
                        {
 
100
                                var expression_statement = node as ExpressionStatement;
 
101
                                if (expression_statement == null)
 
102
                                        return false;
 
103
 
 
104
                                switch (state) {
 
105
                                        case State.Begin:
 
106
                                        case State.WhileBody:
 
107
                                                if (!VisitAssignExpression (expression_statement.Expression))
 
108
                                                        return false;
 
109
                                                break;
 
110
 
 
111
                                        case State.IfBody:
 
112
                                                if (!VisitMethodInvocationExpression (expression_statement.Expression))
 
113
                                                        return false;
 
114
                                                break;
 
115
                                }
 
116
 
 
117
                                return true;
 
118
                        }
 
119
 
 
120
                        bool VisitAssignExpression (Expression node)
 
121
                        {
 
122
                                var assign_expression = node as AssignExpression;
 
123
                                if (assign_expression == null)
 
124
                                        return false;
 
125
 
 
126
                                if (!VisitVariableReferenceExpression (assign_expression.Target))
 
127
                                        return false;
 
128
 
 
129
                                if (!VisitMethodInvocationExpression (assign_expression.Expression))
 
130
                                        return false;
 
131
 
 
132
                                return true;
 
133
                        }
 
134
 
 
135
                        bool VisitTryStatement (Statement node)
 
136
                        {
 
137
                                var try_statement = node as TryStatement;
 
138
                                if (try_statement == null)
 
139
                                        return false;
 
140
 
 
141
                                if (!IsValidTryStatement (try_statement))
 
142
                                        return false;
 
143
 
 
144
                                if (!VisitWhileStatement (try_statement.Try.Statements [0]))
 
145
                                        return false;
 
146
 
 
147
                                if (!VisitIfStatement (try_statement.Finally.Statements [0]))
 
148
                                        return false;
 
149
 
 
150
                                return true;
 
151
                        }
 
152
 
 
153
                        bool VisitIfStatement (Statement statement)
 
154
                        {
 
155
                                var if_statement = statement as IfStatement;
 
156
                                if (if_statement == null || if_statement.Else != null || if_statement.Then.Statements.Count != 1)
 
157
                                        return false;
 
158
 
 
159
                                var binary_expression = if_statement.Condition as BinaryExpression;
 
160
                                if (binary_expression == null || binary_expression.Operator != BinaryOperator.ValueInequality)
 
161
                                        return false;
 
162
 
 
163
                                var enumerator_reference = binary_expression.Left as VariableReferenceExpression;
 
164
                                if (enumerator_reference == null || !IsEnumerator (enumerator_reference))
 
165
                                        return false;
 
166
 
 
167
                                var null_literal = binary_expression.Right as LiteralExpression;
 
168
                                if (null_literal == null || null_literal.Value != null)
 
169
                                        return false;
 
170
 
 
171
                                state = State.IfBody;
 
172
 
 
173
                                if (!VisitExpressionStatement (if_statement.Then.Statements [0]))
 
174
                                        return false;
 
175
 
 
176
                                return true;
 
177
                        }
 
178
 
 
179
                        bool VisitWhileStatement (Statement node)
 
180
                        {
 
181
                                var while_statement = node as WhileStatement;
 
182
                                if (while_statement == null || while_statement.Body.Statements.Count < 1)
 
183
                                        return false;
 
184
 
 
185
                                state = State.WhileCondition;
 
186
 
 
187
                                if (!VisitMethodInvocationExpression (while_statement.Condition))
 
188
                                        return false;
 
189
 
 
190
                                state = State.WhileBody;
 
191
 
 
192
                                if (!VisitExpressionStatement (while_statement.Body.Statements [0]))
 
193
                                        return false;
 
194
 
 
195
                                this.while_body = new BlockStatement ();
 
196
                                for (int i = 1; i < while_statement.Body.Statements.Count; i++) {
 
197
                                        this.while_body.Statements.Add (while_statement.Body.Statements [i]);
 
198
                                }
 
199
 
 
200
                                return true;
 
201
                        }
 
202
 
 
203
                        bool VisitMethodInvocationExpression (Expression node)
 
204
                        {
 
205
                                var invocation_expression = node as MethodInvocationExpression;
 
206
                                if (invocation_expression == null)
 
207
                                        return false;
 
208
 
 
209
                                var method_reference_expression = invocation_expression.Method as MethodReferenceExpression;
 
210
                                if (method_reference_expression == null)
 
211
                                        return false;
 
212
 
 
213
                                // todo : use a resolver for method calls
 
214
                                switch (state) {
 
215
                                        case State.Begin:
 
216
                                                if (method_reference_expression.Method.Name != "GetEnumerator")
 
217
                                                        return false;
 
218
                                                this.source = method_reference_expression.Target;
 
219
                                                break;
 
220
 
 
221
                                        case State.WhileCondition:
 
222
                                                if (!IsCallOnEnumerator (method_reference_expression, "MoveNext"))
 
223
                                                        return false;
 
224
                                                break;
 
225
 
 
226
                                        case State.WhileBody:
 
227
                                                if (!IsCallOnEnumerator (method_reference_expression, "get_Current"))
 
228
                                                        return false;
 
229
                                                break;
 
230
 
 
231
                                        case State.IfBody:
 
232
                                                if (!IsCallOnEnumerator (method_reference_expression, "Dispose"))
 
233
                                                        return false;
 
234
                                                break;
 
235
                                }
 
236
 
 
237
                                return true;
 
238
                        }
 
239
 
 
240
                        bool VisitVariableReferenceExpression (Expression node)
 
241
                        {
 
242
                                var variable_reference_expression = node as VariableReferenceExpression;
 
243
                                if (variable_reference_expression == null)
 
244
                                        return false;
 
245
 
 
246
                                switch (state) {
 
247
                                        case State.Begin:
 
248
                                                this.enumerator = variable_reference_expression.Variable;
 
249
                                                break;
 
250
 
 
251
                                        case State.WhileBody:
 
252
                                                this.variable = variable_reference_expression.Variable as VariableDefinition;
 
253
                                                break;
 
254
                                }
 
255
 
 
256
                                return true;
 
257
                        }
 
258
 
 
259
                        bool IsCallOnEnumerator (MethodReferenceExpression method_reference_expression, string method_name)
 
260
                        {
 
261
                                if (method_reference_expression.Method.Name != method_name)
 
262
                                        return false;
 
263
                                if (!IsEnumerator (method_reference_expression.Target))
 
264
                                        return false;
 
265
                                return true;
 
266
                        }
 
267
 
 
268
                        bool IsEnumerator (Expression node)
 
269
                        {
 
270
                                var variable_reference = node as VariableReferenceExpression;
 
271
                                if (variable_reference == null || variable_reference.Variable != this.enumerator)
 
272
                                        return false;
 
273
                                return true;
 
274
                        }
 
275
 
 
276
                        static bool IsValidTryStatement (TryStatement try_statement)
 
277
                        {
 
278
                                return try_statement.CatchClauses.Count == 0 &&
 
279
                                       try_statement.Try.Statements.Count == 1 &&
 
280
                                       try_statement.Finally != null &&
 
281
                                       try_statement.Finally.Statements.Count == 1;
 
282
                        }
 
283
                }
 
284
        }
 
285
}
 
 
b'\\ No newline at end of file'