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 services.src.refactoring.extract_local; | 5 library services.src.refactoring.extract_local; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:analysis_server/src/protocol.dart' hide Element; | 9 import 'package:analysis_server/src/protocol.dart' hide Element; |
10 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; | 10 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 String declarationSource = '$keyword $name = '; | 122 String declarationSource = '$keyword $name = '; |
123 SourceEdit edit = | 123 SourceEdit edit = |
124 new SourceEdit(singleExpression.offset, 0, declarationSource); | 124 new SourceEdit(singleExpression.offset, 0, declarationSource); |
125 change.addEdit(file, edit); | 125 change.addEdit(file, edit); |
126 return new Future.value(change); | 126 return new Future.value(change); |
127 } | 127 } |
128 // add variable declaration | 128 // add variable declaration |
129 { | 129 { |
130 String declarationSource; | 130 String declarationSource; |
131 if (stringLiteralPart != null) { | 131 if (stringLiteralPart != null) { |
132 declarationSource = "var ${name} = '${stringLiteralPart}';"; | 132 declarationSource = "var $name = '$stringLiteralPart';"; |
133 } else { | 133 } else { |
134 String keyword = _declarationKeyword; | 134 String keyword = _declarationKeyword; |
135 String initializerSource = utils.getRangeText(selectionRange); | 135 String initializerSource = utils.getRangeText(selectionRange); |
136 declarationSource = "${keyword} ${name} = ${initializerSource};"; | 136 declarationSource = "$keyword $name = $initializerSource;"; |
137 } | 137 } |
| 138 String eol = utils.endOfLine; |
138 // prepare location for declaration | 139 // prepare location for declaration |
139 Statement targetStatement = _findTargetStatement(occurrences); | 140 AstNode target_; |
140 String prefix = utils.getNodePrefix(targetStatement); | 141 { |
| 142 List<AstNode> nodes = _findNodes(occurrences); |
| 143 AstNode commonParent = getNearestCommonAncestor(nodes); |
| 144 if (commonParent is Block) { |
| 145 List<AstNode> firstParents = getParents(nodes[0]); |
| 146 int commonIndex = firstParents.indexOf(commonParent); |
| 147 target_ = firstParents[commonIndex + 1]; |
| 148 } else { |
| 149 target_ = _getEnclosingExpressionBody(commonParent); |
| 150 if (target_ == null) { |
| 151 target_ = commonParent.getAncestor((node) => node is Statement); |
| 152 } |
| 153 } |
| 154 } |
| 155 AstNode target = target_; |
141 // insert variable declaration | 156 // insert variable declaration |
142 String eol = utils.endOfLine; | 157 if (target is Statement) { |
143 SourceEdit edit = new SourceEdit( | 158 String prefix = utils.getNodePrefix(target); |
144 targetStatement.offset, | 159 SourceEdit edit = |
145 0, | 160 new SourceEdit(target.offset, 0, declarationSource + eol + prefix); |
146 '${declarationSource}${eol}${prefix}'); | 161 change.addEdit(file, edit); |
147 change.addEdit(file, edit); | 162 } else if (target is ExpressionFunctionBody) { |
| 163 String prefix = utils.getNodePrefix(target.parent); |
| 164 String indent = utils.getIndent(1); |
| 165 String declStatement = prefix + indent + declarationSource + eol; |
| 166 String exprStatement = prefix + indent + 'return '; |
| 167 Expression expr = target.expression; |
| 168 change.addEdit( |
| 169 file, |
| 170 new SourceEdit( |
| 171 target.offset, |
| 172 expr.offset - target.offset, |
| 173 '{' + eol + declStatement + exprStatement)); |
| 174 change.addEdit( |
| 175 file, |
| 176 new SourceEdit(expr.end, 0, ';' + eol + prefix + '}')); |
| 177 } |
148 } | 178 } |
149 // prepare replacement | 179 // prepare replacement |
150 String occurrenceReplacement = name; | 180 String occurrenceReplacement = name; |
151 if (stringLiteralPart != null) { | 181 if (stringLiteralPart != null) { |
152 occurrenceReplacement = "\${$name}"; | 182 occurrenceReplacement = "\${$name}"; |
153 } | 183 } |
154 // replace occurrences with variable reference | 184 // replace occurrences with variable reference |
155 for (SourceRange range in occurrences) { | 185 for (SourceRange range in occurrences) { |
156 SourceEdit edit = new SourceEdit.range(range, occurrenceReplacement); | 186 SourceEdit edit = new SourceEdit.range(range, occurrenceReplacement); |
157 change.addEdit(file, edit); | 187 change.addEdit(file, edit); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 List<AstNode> _findNodes(List<SourceRange> ranges) { | 264 List<AstNode> _findNodes(List<SourceRange> ranges) { |
235 List<AstNode> nodes = <AstNode>[]; | 265 List<AstNode> nodes = <AstNode>[]; |
236 for (SourceRange range in ranges) { | 266 for (SourceRange range in ranges) { |
237 AstNode node = new NodeLocator.con1(range.offset).searchWithin(unit); | 267 AstNode node = new NodeLocator.con1(range.offset).searchWithin(unit); |
238 nodes.add(node); | 268 nodes.add(node); |
239 } | 269 } |
240 return nodes; | 270 return nodes; |
241 } | 271 } |
242 | 272 |
243 /** | 273 /** |
244 * Returns the [Statement] such that variable declaration added before it is | 274 * Returns the [ExpressionFunctionBody] that encloses [node], or `null` |
245 * visible at all given occurrences. | 275 * if [node] is not enclosed with an [ExpressionFunctionBody]. |
246 */ | 276 */ |
247 Statement _findTargetStatement(List<SourceRange> occurrences) { | 277 ExpressionFunctionBody _getEnclosingExpressionBody(AstNode node) { |
248 List<AstNode> nodes = _findNodes(occurrences); | 278 while (node != null) { |
249 List<AstNode> firstParents = getParents(nodes[0]); | 279 if (node is Statement) { |
250 AstNode commonParent = getNearestCommonAncestor(nodes); | 280 return null; |
251 if (commonParent is Block) { | 281 } |
252 int commonIndex = firstParents.indexOf(commonParent); | 282 if (node is ExpressionFunctionBody) { |
253 return firstParents[commonIndex + 1] as Statement; | 283 return node; |
254 } else { | 284 } |
255 return commonParent.getAncestor((node) => node is Statement); | 285 node = node.parent; |
256 } | 286 } |
| 287 return null; |
257 } | 288 } |
258 | 289 |
259 /** | 290 /** |
260 * Checks if it is OK to extract the node with the given [SourceRange]. | 291 * Checks if it is OK to extract the node with the given [SourceRange]. |
261 */ | 292 */ |
262 bool _isExtractable(SourceRange range) { | 293 bool _isExtractable(SourceRange range) { |
263 _ExtractExpressionAnalyzer analyzer = new _ExtractExpressionAnalyzer(range); | 294 _ExtractExpressionAnalyzer analyzer = new _ExtractExpressionAnalyzer(range); |
264 utils.unit.accept(analyzer); | 295 utils.unit.accept(analyzer); |
265 return analyzer.status.isOK; | 296 return analyzer.status.isOK; |
266 } | 297 } |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 Token startToken = nodeTokens[startTokenIndex]; | 559 Token startToken = nodeTokens[startTokenIndex]; |
529 Token endToken = nodeTokens[endTokenIndex]; | 560 Token endToken = nodeTokens[endTokenIndex]; |
530 // add occurrence range | 561 // add occurrence range |
531 int occuStart = nodeOffset + startToken.offset; | 562 int occuStart = nodeOffset + startToken.offset; |
532 int occuEnd = nodeOffset + endToken.end; | 563 int occuEnd = nodeOffset + endToken.end; |
533 SourceRange occuRange = rangeStartEnd(occuStart, occuEnd); | 564 SourceRange occuRange = rangeStartEnd(occuStart, occuEnd); |
534 _addOccurrence(occuRange); | 565 _addOccurrence(occuRange); |
535 } | 566 } |
536 } | 567 } |
537 } | 568 } |
OLD | NEW |