~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertParenthesesVisitor.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
ļ»æ// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
2
 
// 
3
 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
 
// software and associated documentation files (the "Software"), to deal in the Software
5
 
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
 
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
 
// to whom the Software is furnished to do so, subject to the following conditions:
8
 
// 
9
 
// The above copyright notice and this permission notice shall be included in all copies or
10
 
// substantial portions of the Software.
11
 
// 
12
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
 
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
 
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
 
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
 
// DEALINGS IN THE SOFTWARE.
18
 
 
19
 
using System;
20
 
 
21
 
namespace ICSharpCode.NRefactory.CSharp
22
 
{
23
 
        /// <summary>
24
 
        /// Inserts the parentheses into the AST that are needed to ensure the AST can be printed correctly.
25
 
        /// For example, if the AST contains
26
 
        /// BinaryOperatorExpresson(2, Mul, BinaryOperatorExpression(1, Add, 1))); printing that AST
27
 
        /// would incorrectly result in "2 * 1 + 1". By running InsertParenthesesVisitor, the necessary
28
 
        /// parentheses are inserted: "2 * (1 + 1)".
29
 
        /// </summary>
30
 
        public class InsertParenthesesVisitor : DepthFirstAstVisitor
31
 
        {
32
 
                /// <summary>
33
 
                /// Gets/Sets whether the visitor should insert parentheses to make the code better looking.
34
 
                /// If this property is false, it will insert parentheses only where strictly required by the language spec.
35
 
                /// </summary>
36
 
                public bool InsertParenthesesForReadability { get; set; }
37
 
                
38
 
                const int Primary = 16;
39
 
                const int QueryOrLambda = 15;
40
 
                const int Unary = 14;
41
 
                const int RelationalAndTypeTesting = 10;
42
 
                const int Equality = 9;
43
 
                const int Conditional = 2;
44
 
                const int Assignment = 1;
45
 
                
46
 
                /// <summary>
47
 
                /// Gets the row number in the C# 4.0 spec operator precedence table.
48
 
                /// </summary>
49
 
                static int GetPrecedence(Expression expr)
50
 
                {
51
 
                        // Note: the operator precedence table on MSDN is incorrect
52
 
                        if (expr is QueryExpression) {
53
 
                                // Not part of the table in the C# spec, but we need to ensure that queries within
54
 
                                // primary expressions get parenthesized.
55
 
                                return QueryOrLambda;
56
 
                        }
57
 
                        UnaryOperatorExpression uoe = expr as UnaryOperatorExpression;
58
 
                        if (uoe != null) {
59
 
                                if (uoe.Operator == UnaryOperatorType.PostDecrement || uoe.Operator == UnaryOperatorType.PostIncrement)
60
 
                                        return Primary;
61
 
                                else
62
 
                                        return Unary;
63
 
                        }
64
 
                        if (expr is CastExpression)
65
 
                                return Unary;
66
 
                        BinaryOperatorExpression boe = expr as BinaryOperatorExpression;
67
 
                        if (boe != null) {
68
 
                                switch (boe.Operator) {
69
 
                                        case BinaryOperatorType.Multiply:
70
 
                                        case BinaryOperatorType.Divide:
71
 
                                        case BinaryOperatorType.Modulus:
72
 
                                                return 13; // multiplicative
73
 
                                        case BinaryOperatorType.Add:
74
 
                                        case BinaryOperatorType.Subtract:
75
 
                                                return 12; // additive
76
 
                                        case BinaryOperatorType.ShiftLeft:
77
 
                                        case BinaryOperatorType.ShiftRight:
78
 
                                                return 11;
79
 
                                        case BinaryOperatorType.GreaterThan:
80
 
                                        case BinaryOperatorType.GreaterThanOrEqual:
81
 
                                        case BinaryOperatorType.LessThan:
82
 
                                        case BinaryOperatorType.LessThanOrEqual:
83
 
                                                return RelationalAndTypeTesting;
84
 
                                        case BinaryOperatorType.Equality:
85
 
                                        case BinaryOperatorType.InEquality:
86
 
                                                return Equality;
87
 
                                        case BinaryOperatorType.BitwiseAnd:
88
 
                                                return 8;
89
 
                                        case BinaryOperatorType.ExclusiveOr:
90
 
                                                return 7;
91
 
                                        case BinaryOperatorType.BitwiseOr:
92
 
                                                return 6;
93
 
                                        case BinaryOperatorType.ConditionalAnd:
94
 
                                                return 5;
95
 
                                        case BinaryOperatorType.ConditionalOr:
96
 
                                                return 4;
97
 
                                        case BinaryOperatorType.NullCoalescing:
98
 
                                                return 3;
99
 
                                        default:
100
 
                                                throw new NotSupportedException("Invalid value for BinaryOperatorType");
101
 
                                }
102
 
                        }
103
 
                        if (expr is IsExpression || expr is AsExpression)
104
 
                                return RelationalAndTypeTesting;
105
 
                        if (expr is ConditionalExpression)
106
 
                                return Conditional;
107
 
                        if (expr is AssignmentExpression || expr is LambdaExpression)
108
 
                                return Assignment;
109
 
                        // anything else: primary expression
110
 
                        return Primary;
111
 
                }
112
 
                
113
 
                /// <summary>
114
 
                /// Parenthesizes the expression if it does not have the minimum required precedence.
115
 
                /// </summary>
116
 
                static void ParenthesizeIfRequired(Expression expr, int minimumPrecedence)
117
 
                {
118
 
                        if (GetPrecedence(expr) < minimumPrecedence) {
119
 
                                Parenthesize(expr);
120
 
                        }
121
 
                }
122
 
 
123
 
                static void Parenthesize(Expression expr)
124
 
                {
125
 
                        expr.ReplaceWith(e => new ParenthesizedExpression { Expression = e });
126
 
                }
127
 
                
128
 
                // Primary expressions
129
 
                public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
130
 
                {
131
 
                        ParenthesizeIfRequired(memberReferenceExpression.Target, Primary);
132
 
                        base.VisitMemberReferenceExpression(memberReferenceExpression);
133
 
                }
134
 
                
135
 
                public override void VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression)
136
 
                {
137
 
                        ParenthesizeIfRequired(pointerReferenceExpression.Target, Primary);
138
 
                        base.VisitPointerReferenceExpression(pointerReferenceExpression);
139
 
                }
140
 
                
141
 
                public override void VisitInvocationExpression(InvocationExpression invocationExpression)
142
 
                {
143
 
                        ParenthesizeIfRequired(invocationExpression.Target, Primary);
144
 
                        base.VisitInvocationExpression(invocationExpression);
145
 
                }
146
 
                
147
 
                public override void VisitIndexerExpression(IndexerExpression indexerExpression)
148
 
                {
149
 
                        ParenthesizeIfRequired(indexerExpression.Target, Primary);
150
 
                        ArrayCreateExpression ace = indexerExpression.Target as ArrayCreateExpression;
151
 
                        if (ace != null && (InsertParenthesesForReadability || ace.Initializer.IsNull)) {
152
 
                                // require parentheses for "(new int[1])[0]"
153
 
                                Parenthesize(indexerExpression.Target);
154
 
                        }
155
 
                        base.VisitIndexerExpression(indexerExpression);
156
 
                }
157
 
                
158
 
                // Unary expressions
159
 
                public override void VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression)
160
 
                {
161
 
                        ParenthesizeIfRequired(unaryOperatorExpression.Expression, GetPrecedence(unaryOperatorExpression));
162
 
                        UnaryOperatorExpression child = unaryOperatorExpression.Expression as UnaryOperatorExpression;
163
 
                        if (child != null && InsertParenthesesForReadability)
164
 
                                Parenthesize(child);
165
 
                        base.VisitUnaryOperatorExpression(unaryOperatorExpression);
166
 
                }
167
 
                
168
 
                public override void VisitCastExpression(CastExpression castExpression)
169
 
                {
170
 
                        ParenthesizeIfRequired(castExpression.Expression, InsertParenthesesForReadability ? Primary : Unary);
171
 
                        // There's a nasty issue in the C# grammar: cast expressions including certain operators are ambiguous in some cases
172
 
                        // "(int)-1" is fine, but "(A)-b" is not a cast.
173
 
                        UnaryOperatorExpression uoe = castExpression.Expression as UnaryOperatorExpression;
174
 
                        if (uoe != null && !(uoe.Operator == UnaryOperatorType.BitNot || uoe.Operator == UnaryOperatorType.Not)) {
175
 
                                if (TypeCanBeMisinterpretedAsExpression(castExpression.Type)) {
176
 
                                        Parenthesize(castExpression.Expression);
177
 
                                }
178
 
                        }
179
 
                        // The above issue can also happen with PrimitiveExpressions representing negative values:
180
 
                        PrimitiveExpression pe = castExpression.Expression as PrimitiveExpression;
181
 
                        if (pe != null && pe.Value != null && TypeCanBeMisinterpretedAsExpression(castExpression.Type)) {
182
 
                                TypeCode typeCode = Type.GetTypeCode(pe.Value.GetType());
183
 
                                switch (typeCode) {
184
 
                                        case TypeCode.SByte:
185
 
                                                if ((sbyte)pe.Value < 0)
186
 
                                                        Parenthesize(castExpression.Expression);
187
 
                                                break;
188
 
                                        case TypeCode.Int16:
189
 
                                                if ((short)pe.Value < 0)
190
 
                                                        Parenthesize(castExpression.Expression);
191
 
                                                break;
192
 
                                        case TypeCode.Int32:
193
 
                                                if ((int)pe.Value < 0)
194
 
                                                        Parenthesize(castExpression.Expression);
195
 
                                                break;
196
 
                                        case TypeCode.Int64:
197
 
                                                if ((long)pe.Value < 0)
198
 
                                                        Parenthesize(castExpression.Expression);
199
 
                                                break;
200
 
                                        case TypeCode.Single:
201
 
                                                if ((float)pe.Value < 0)
202
 
                                                        Parenthesize(castExpression.Expression);
203
 
                                                break;
204
 
                                        case TypeCode.Double:
205
 
                                                if ((double)pe.Value < 0)
206
 
                                                        Parenthesize(castExpression.Expression);
207
 
                                                break;
208
 
                                        case TypeCode.Decimal:
209
 
                                                if ((decimal)pe.Value < 0)
210
 
                                                        Parenthesize(castExpression.Expression);
211
 
                                                break;
212
 
                                }
213
 
                        }
214
 
                        base.VisitCastExpression(castExpression);
215
 
                }
216
 
                
217
 
                static bool TypeCanBeMisinterpretedAsExpression(AstType type)
218
 
                {
219
 
                        // SimpleTypes can always be misinterpreted as IdentifierExpressions
220
 
                        // MemberTypes can be misinterpreted as MemberReferenceExpressions if they don't use double colon
221
 
                        // PrimitiveTypes or ComposedTypes can never be misinterpreted as expressions.
222
 
                        MemberType mt = type as MemberType;
223
 
                        if (mt != null)
224
 
                                return !mt.IsDoubleColon;
225
 
                        else
226
 
                                return type is SimpleType;
227
 
                }
228
 
                
229
 
                // Binary Operators
230
 
                public override void VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
231
 
                {
232
 
                        int precedence = GetPrecedence(binaryOperatorExpression);
233
 
                        if (binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing) {
234
 
                                if (InsertParenthesesForReadability) {
235
 
                                        ParenthesizeIfRequired(binaryOperatorExpression.Left, Primary);
236
 
                                        ParenthesizeIfRequired(binaryOperatorExpression.Right, Primary);
237
 
                                } else {
238
 
                                        // ?? is right-associate
239
 
                                        ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence + 1);
240
 
                                        ParenthesizeIfRequired(binaryOperatorExpression.Right, precedence);
241
 
                                }
242
 
                        } else {
243
 
                                if (InsertParenthesesForReadability && precedence < Equality) {
244
 
                                        // In readable mode, boost the priority of the left-hand side if the operator
245
 
                                        // there isn't the same as the operator on this expression.
246
 
                                        if (GetBinaryOperatorType(binaryOperatorExpression.Left) == binaryOperatorExpression.Operator) {
247
 
                                                ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence);
248
 
                                        } else {
249
 
                                                ParenthesizeIfRequired(binaryOperatorExpression.Left, Equality);
250
 
                                        }
251
 
                                        ParenthesizeIfRequired(binaryOperatorExpression.Right, Equality);
252
 
                                } else {
253
 
                                        // all other binary operators are left-associative
254
 
                                        ParenthesizeIfRequired(binaryOperatorExpression.Left, precedence);
255
 
                                        ParenthesizeIfRequired(binaryOperatorExpression.Right, precedence + 1);
256
 
                                }
257
 
                        }
258
 
                        base.VisitBinaryOperatorExpression(binaryOperatorExpression);
259
 
                }
260
 
                
261
 
                BinaryOperatorType? GetBinaryOperatorType(Expression expr)
262
 
                {
263
 
                        BinaryOperatorExpression boe = expr as BinaryOperatorExpression;
264
 
                        if (boe != null)
265
 
                                return boe.Operator;
266
 
                        else
267
 
                                return null;
268
 
                }
269
 
                
270
 
                public override void VisitIsExpression(IsExpression isExpression)
271
 
                {
272
 
                        if (InsertParenthesesForReadability) {
273
 
                                // few people know the precedence of 'is', so always put parentheses in nice-looking mode.
274
 
                                ParenthesizeIfRequired(isExpression.Expression, Primary);
275
 
                        } else {
276
 
                                ParenthesizeIfRequired(isExpression.Expression, RelationalAndTypeTesting);
277
 
                        }
278
 
                        base.VisitIsExpression(isExpression);
279
 
                }
280
 
                
281
 
                public override void VisitAsExpression(AsExpression asExpression)
282
 
                {
283
 
                        if (InsertParenthesesForReadability) {
284
 
                                // few people know the precedence of 'as', so always put parentheses in nice-looking mode.
285
 
                                ParenthesizeIfRequired(asExpression.Expression, Primary);
286
 
                        } else {
287
 
                                ParenthesizeIfRequired(asExpression.Expression, RelationalAndTypeTesting);
288
 
                        }
289
 
                        base.VisitAsExpression(asExpression);
290
 
                }
291
 
                
292
 
                // Conditional operator
293
 
                public override void VisitConditionalExpression(ConditionalExpression conditionalExpression)
294
 
                {
295
 
                        // Associativity here is a bit tricky:
296
 
                        // (a ? b : c ? d : e) == (a ? b : (c ? d : e))
297
 
                        // (a ? b ? c : d : e) == (a ? (b ? c : d) : e)
298
 
                        // Only ((a ? b : c) ? d : e) strictly needs the additional parentheses
299
 
                        if (InsertParenthesesForReadability) {
300
 
                                // Precedence of ?: can be confusing; so always put parentheses in nice-looking mode.
301
 
                                ParenthesizeIfRequired(conditionalExpression.Condition, Primary);
302
 
                                ParenthesizeIfRequired(conditionalExpression.TrueExpression, Primary);
303
 
                                ParenthesizeIfRequired(conditionalExpression.FalseExpression, Primary);
304
 
                        } else {
305
 
                                ParenthesizeIfRequired(conditionalExpression.Condition, Conditional + 1);
306
 
                                ParenthesizeIfRequired(conditionalExpression.TrueExpression, Conditional);
307
 
                                ParenthesizeIfRequired(conditionalExpression.FalseExpression, Conditional);
308
 
                        }
309
 
                        base.VisitConditionalExpression(conditionalExpression);
310
 
                }
311
 
                
312
 
                public override void VisitAssignmentExpression(AssignmentExpression assignmentExpression)
313
 
                {
314
 
                        // assignment is right-associative
315
 
                        ParenthesizeIfRequired(assignmentExpression.Left, Assignment + 1);
316
 
                        if (InsertParenthesesForReadability) {
317
 
                                ParenthesizeIfRequired(assignmentExpression.Right, RelationalAndTypeTesting + 1);
318
 
                        } else {
319
 
                                ParenthesizeIfRequired(assignmentExpression.Right, Assignment);
320
 
                        }
321
 
                        base.VisitAssignmentExpression(assignmentExpression);
322
 
                }
323
 
                
324
 
                // don't need to handle lambdas, they have lowest precedence and unambiguous associativity
325
 
                
326
 
                public override void VisitQueryExpression(QueryExpression queryExpression)
327
 
                {
328
 
                        // Query expressions are strange beasts:
329
 
                        // "var a = -from b in c select d;" is valid, so queries bind stricter than unary expressions.
330
 
                        // However, the end of the query is greedy. So their start sort of has a high precedence,
331
 
                        // while their end has a very low precedence. We handle this by checking whether a query is used
332
 
                        // as left part of a binary operator, and parenthesize it if required.
333
 
                        if (queryExpression.Role == BinaryOperatorExpression.LeftRole)
334
 
                                Parenthesize(queryExpression);
335
 
                        if (queryExpression.Parent is IsExpression || queryExpression.Parent is AsExpression)
336
 
                                Parenthesize(queryExpression);
337
 
                        if (InsertParenthesesForReadability) {
338
 
                                // when readability is desired, always parenthesize query expressions within unary or binary operators
339
 
                                if (queryExpression.Parent is UnaryOperatorExpression || queryExpression.Parent is BinaryOperatorExpression)
340
 
                                        Parenthesize(queryExpression);
341
 
                        }
342
 
                        base.VisitQueryExpression(queryExpression);
343
 
                }
344
 
        }
345
 
}