OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart_style.src.call_chain_visitor; | 5 library dart_style.src.call_chain_visitor; |
6 | 6 |
7 import 'package:analyzer/analyzer.dart'; | 7 import 'package:analyzer/analyzer.dart'; |
8 | 8 |
9 import 'argument_list_visitor.dart'; | 9 import 'argument_list_visitor.dart'; |
10 import 'rule/argument.dart'; | 10 import 'rule/argument.dart'; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 /// operators and must be a [MethodInvocation], [PropertyAccess] or | 44 /// operators and must be a [MethodInvocation], [PropertyAccess] or |
45 /// [PrefixedIdentifier]. | 45 /// [PrefixedIdentifier]. |
46 factory CallChainVisitor(SourceVisitor visitor, Expression node) { | 46 factory CallChainVisitor(SourceVisitor visitor, Expression node) { |
47 var target; | 47 var target; |
48 | 48 |
49 // Recursively walk the chain of calls and turn the tree into a list. | 49 // Recursively walk the chain of calls and turn the tree into a list. |
50 var calls = []; | 50 var calls = []; |
51 flatten(expression) { | 51 flatten(expression) { |
52 target = expression; | 52 target = expression; |
53 | 53 |
54 if (expression is MethodInvocation && expression.target != null) { | 54 // Treat index expressions where the target is a valid call in a method |
55 flatten(expression.target); | 55 // chain as being part of the call. Handles cases like: |
| 56 // |
| 57 // receiver |
| 58 // .property |
| 59 // .property[0] |
| 60 // .property |
| 61 // .property; |
| 62 var call = expression; |
| 63 while (call is IndexExpression) call = call.target; |
| 64 |
| 65 if (call is MethodInvocation && call.target != null) { |
| 66 flatten(call.target); |
56 calls.add(expression); | 67 calls.add(expression); |
57 } else if (expression is PropertyAccess && expression.target != null) { | 68 } else if (call is PropertyAccess && call.target != null) { |
58 flatten(expression.target); | 69 flatten(call.target); |
59 calls.add(expression); | 70 calls.add(expression); |
60 } else if (expression is PrefixedIdentifier) { | 71 } else if (call is PrefixedIdentifier) { |
61 flatten(expression.prefix); | 72 flatten(call.prefix); |
62 calls.add(expression); | 73 calls.add(expression); |
63 } | 74 } |
64 } | 75 } |
65 | 76 |
66 flatten(node); | 77 flatten(node); |
67 | 78 |
68 // An expression that starts with a series of dotted names gets treated a | 79 // An expression that starts with a series of dotted names gets treated a |
69 // little specially. We don't force leading properties to split with the | 80 // little specially. We don't force leading properties to split with the |
70 // rest of the chain. Allows code like: | 81 // rest of the chain. Allows code like: |
71 // | 82 // |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 } | 139 } |
129 | 140 |
130 _disableRule(); | 141 _disableRule(); |
131 _endSpan(); | 142 _endSpan(); |
132 | 143 |
133 if (unnest) _visitor.builder.unnest(); | 144 if (unnest) _visitor.builder.unnest(); |
134 } | 145 } |
135 | 146 |
136 /// Writes [call], which must be one of the supported expression types. | 147 /// Writes [call], which must be one of the supported expression types. |
137 void _writeCall(Expression call) { | 148 void _writeCall(Expression call) { |
138 if (call is MethodInvocation) { | 149 if (call is IndexExpression) { |
| 150 _visitor.builder.nestExpression(); |
| 151 _writeCall(call.target); |
| 152 _visitor.finishIndexExpression(call); |
| 153 _visitor.builder.unnest(); |
| 154 } else if (call is MethodInvocation) { |
139 _writeInvocation(call); | 155 _writeInvocation(call); |
140 } else if (call is PropertyAccess) { | 156 } else if (call is PropertyAccess) { |
141 _writePropertyAccess(call); | 157 _visitor.token(call.operator); |
| 158 _visitor.visit(call.propertyName); |
142 } else if (call is PrefixedIdentifier) { | 159 } else if (call is PrefixedIdentifier) { |
143 _writePrefixedIdentifier(call); | 160 _visitor.token(call.period); |
| 161 _visitor.visit(call.identifier); |
144 } else { | 162 } else { |
145 // Unexpected type. | 163 // Unexpected type. |
146 assert(false); | 164 assert(false); |
147 } | 165 } |
148 } | 166 } |
149 | 167 |
150 void _writeInvocation(MethodInvocation invocation) { | 168 void _writeInvocation(MethodInvocation invocation) { |
151 _visitor.token(invocation.operator); | 169 _visitor.token(invocation.operator); |
152 _visitor.token(invocation.methodName.token); | 170 _visitor.token(invocation.methodName.token); |
153 | 171 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 _calls.length == 1 && | 222 _calls.length == 1 && |
205 _target is SimpleIdentifier) { | 223 _target is SimpleIdentifier) { |
206 _endSpan(); | 224 _endSpan(); |
207 } | 225 } |
208 | 226 |
209 _visitor.visit(invocation.argumentList); | 227 _visitor.visit(invocation.argumentList); |
210 | 228 |
211 if (args.nestMethodArguments) _visitor.builder.endBlockArgumentNesting(); | 229 if (args.nestMethodArguments) _visitor.builder.endBlockArgumentNesting(); |
212 } | 230 } |
213 | 231 |
214 void _writePropertyAccess(PropertyAccess property) { | |
215 _visitor.token(property.operator); | |
216 _visitor.visit(property.propertyName); | |
217 } | |
218 | |
219 void _writePrefixedIdentifier(PrefixedIdentifier prefix) { | |
220 _visitor.token(prefix.period); | |
221 _visitor.visit(prefix.identifier); | |
222 } | |
223 | |
224 /// If a [Rule] for the method chain is currently active, ends it. | 232 /// If a [Rule] for the method chain is currently active, ends it. |
225 void _disableRule() { | 233 void _disableRule() { |
226 if (_ruleEnabled == false) return; | 234 if (_ruleEnabled == false) return; |
227 | 235 |
228 _visitor.builder.endRule(); | 236 _visitor.builder.endRule(); |
229 _ruleEnabled = false; | 237 _ruleEnabled = false; |
230 } | 238 } |
231 | 239 |
232 /// Creates a new method chain [Rule] if one is not already active. | 240 /// Creates a new method chain [Rule] if one is not already active. |
233 void _enableRule() { | 241 void _enableRule() { |
234 if (_ruleEnabled) return; | 242 if (_ruleEnabled) return; |
235 | 243 |
236 _visitor.builder.startRule(); | 244 _visitor.builder.startRule(); |
237 _ruleEnabled = true; | 245 _ruleEnabled = true; |
238 } | 246 } |
239 | 247 |
240 /// Ends the span wrapping the call chain if it hasn't ended already. | 248 /// Ends the span wrapping the call chain if it hasn't ended already. |
241 void _endSpan() { | 249 void _endSpan() { |
242 if (_spanEnded) return; | 250 if (_spanEnded) return; |
243 | 251 |
244 _visitor.builder.endSpan(); | 252 _visitor.builder.endSpan(); |
245 _spanEnded = true; | 253 _spanEnded = true; |
246 } | 254 } |
247 } | 255 } |
OLD | NEW |