| 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.inline_local; | 5 library services.src.refactoring.inline_local; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol_server.dart' hide Element; | 9 import 'package:analysis_server/src/protocol_server.dart' hide Element; |
| 10 import 'package:analysis_server/src/services/correction/source_range.dart'; | 10 import 'package:analysis_server/src/services/correction/source_range.dart'; |
| 11 import 'package:analysis_server/src/services/correction/status.dart'; | 11 import 'package:analysis_server/src/services/correction/status.dart'; |
| 12 import 'package:analysis_server/src/services/correction/util.dart'; | 12 import 'package:analysis_server/src/services/correction/util.dart'; |
| 13 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; | 13 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; |
| 14 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
rt'; | 14 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
rt'; |
| 15 import 'package:analysis_server/src/services/search/search_engine.dart'; | 15 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 16 import 'package:analyzer/src/generated/ast.dart'; | 16 import 'package:analyzer/src/generated/ast.dart'; |
| 17 import 'package:analyzer/src/generated/element.dart'; | 17 import 'package:analyzer/src/generated/element.dart'; |
| 18 import 'package:analyzer/src/generated/java_core.dart'; | 18 import 'package:analyzer/src/generated/java_core.dart'; |
| 19 import 'package:analyzer/src/generated/scanner.dart'; | 19 import 'package:analyzer/src/generated/scanner.dart'; |
| 20 import 'package:analyzer/src/generated/source.dart'; | 20 import 'package:analyzer/src/generated/source.dart'; |
| 21 | 21 |
| 22 | |
| 23 /** | 22 /** |
| 24 * [InlineLocalRefactoring] implementation. | 23 * [InlineLocalRefactoring] implementation. |
| 25 */ | 24 */ |
| 26 class InlineLocalRefactoringImpl extends RefactoringImpl implements | 25 class InlineLocalRefactoringImpl extends RefactoringImpl |
| 27 InlineLocalRefactoring { | 26 implements InlineLocalRefactoring { |
| 28 final SearchEngine searchEngine; | 27 final SearchEngine searchEngine; |
| 29 final CompilationUnit unit; | 28 final CompilationUnit unit; |
| 30 final int offset; | 29 final int offset; |
| 31 CompilationUnitElement unitElement; | 30 CompilationUnitElement unitElement; |
| 32 CorrectionUtils utils; | 31 CorrectionUtils utils; |
| 33 | 32 |
| 34 Element _variableElement; | 33 Element _variableElement; |
| 35 VariableDeclaration _variableNode; | 34 VariableDeclaration _variableNode; |
| 36 List<SearchMatch> _references; | 35 List<SearchMatch> _references; |
| 37 | 36 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 if (element is LocalVariableElement) { | 75 if (element is LocalVariableElement) { |
| 77 _variableElement = element; | 76 _variableElement = element; |
| 78 _variableNode = element.node; | 77 _variableNode = element.node; |
| 79 } | 78 } |
| 80 } | 79 } |
| 81 } | 80 } |
| 82 // validate node declaration | 81 // validate node declaration |
| 83 if (!_isVariableDeclaredInStatement()) { | 82 if (!_isVariableDeclaredInStatement()) { |
| 84 result = new RefactoringStatus.fatal( | 83 result = new RefactoringStatus.fatal( |
| 85 'Local variable declaration or reference must be selected ' | 84 'Local variable declaration or reference must be selected ' |
| 86 'to activate this refactoring.'); | 85 'to activate this refactoring.'); |
| 87 return new Future.value(result); | 86 return new Future.value(result); |
| 88 } | 87 } |
| 89 // should have initializer at declaration | 88 // should have initializer at declaration |
| 90 if (_variableNode.initializer == null) { | 89 if (_variableNode.initializer == null) { |
| 91 String message = format( | 90 String message = format( |
| 92 "Local variable '{0}' is not initialized at declaration.", | 91 "Local variable '{0}' is not initialized at declaration.", |
| 93 _variableElement.displayName); | 92 _variableElement.displayName); |
| 94 result = | 93 result = new RefactoringStatus.fatal( |
| 95 new RefactoringStatus.fatal(message, newLocation_fromNode(_variableNod
e)); | 94 message, newLocation_fromNode(_variableNode)); |
| 96 return new Future.value(result); | 95 return new Future.value(result); |
| 97 } | 96 } |
| 98 // prepare references | 97 // prepare references |
| 99 _references = await searchEngine.searchReferences(_variableElement); | 98 _references = await searchEngine.searchReferences(_variableElement); |
| 100 // should not have assignments | 99 // should not have assignments |
| 101 for (SearchMatch reference in _references) { | 100 for (SearchMatch reference in _references) { |
| 102 if (reference.kind != MatchKind.READ) { | 101 if (reference.kind != MatchKind.READ) { |
| 103 String message = format( | 102 String message = format( |
| 104 "Local variable '{0}' is assigned more than once.", | 103 "Local variable '{0}' is assigned more than once.", [ |
| 105 [_variableElement.displayName]); | 104 _variableElement.displayName |
| 105 ]); |
| 106 return new RefactoringStatus.fatal( | 106 return new RefactoringStatus.fatal( |
| 107 message, | 107 message, newLocation_fromMatch(reference)); |
| 108 newLocation_fromMatch(reference)); | |
| 109 } | 108 } |
| 110 } | 109 } |
| 111 // done | 110 // done |
| 112 return result; | 111 return result; |
| 113 } | 112 } |
| 114 | 113 |
| 115 @override | 114 @override |
| 116 Future<SourceChange> createChange() { | 115 Future<SourceChange> createChange() { |
| 117 SourceChange change = new SourceChange(refactoringName); | 116 SourceChange change = new SourceChange(refactoringName); |
| 118 // remove declaration | 117 // remove declaration |
| 119 { | 118 { |
| 120 Statement declarationStatement = | 119 Statement declarationStatement = _variableNode |
| 121 _variableNode.getAncestor((node) => node is VariableDeclarationStateme
nt); | 120 .getAncestor((node) => node is VariableDeclarationStatement); |
| 122 SourceRange range = utils.getLinesRangeStatements([declarationStatement]); | 121 SourceRange range = utils.getLinesRangeStatements([declarationStatement]); |
| 123 doSourceChange_addElementEdit( | 122 doSourceChange_addElementEdit( |
| 124 change, | 123 change, unitElement, newSourceEdit_range(range, '')); |
| 125 unitElement, | |
| 126 newSourceEdit_range(range, '')); | |
| 127 } | 124 } |
| 128 // prepare initializer | 125 // prepare initializer |
| 129 Expression initializer = _variableNode.initializer; | 126 Expression initializer = _variableNode.initializer; |
| 130 String initializerCode = utils.getNodeText(initializer); | 127 String initializerCode = utils.getNodeText(initializer); |
| 131 // replace references | 128 // replace references |
| 132 for (SearchMatch reference in _references) { | 129 for (SearchMatch reference in _references) { |
| 133 SourceRange range = reference.sourceRange; | 130 SourceRange range = reference.sourceRange; |
| 134 // prepare context | 131 // prepare context |
| 135 int offset = range.offset; | 132 int offset = range.offset; |
| 136 AstNode node = utils.findNode(offset); | 133 AstNode node = utils.findNode(offset); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 161 } else { | 158 } else { |
| 162 codeForReference = initializerCode; | 159 codeForReference = initializerCode; |
| 163 } | 160 } |
| 164 } else if (_shouldUseParenthesis(initializer, node)) { | 161 } else if (_shouldUseParenthesis(initializer, node)) { |
| 165 codeForReference = '($initializerCode)'; | 162 codeForReference = '($initializerCode)'; |
| 166 } else { | 163 } else { |
| 167 codeForReference = initializerCode; | 164 codeForReference = initializerCode; |
| 168 } | 165 } |
| 169 // do replace | 166 // do replace |
| 170 doSourceChange_addElementEdit( | 167 doSourceChange_addElementEdit( |
| 171 change, | 168 change, unitElement, newSourceEdit_range(range, codeForReference)); |
| 172 unitElement, | |
| 173 newSourceEdit_range(range, codeForReference)); | |
| 174 } | 169 } |
| 175 // done | 170 // done |
| 176 return new Future.value(change); | 171 return new Future.value(change); |
| 177 } | 172 } |
| 178 | 173 |
| 179 @override | 174 @override |
| 180 bool requiresPreview() => false; | 175 bool requiresPreview() => false; |
| 181 | 176 |
| 182 bool _isVariableDeclaredInStatement() { | 177 bool _isVariableDeclaredInStatement() { |
| 183 if (_variableNode == null) { | 178 if (_variableNode == null) { |
| 184 return false; | 179 return false; |
| 185 } | 180 } |
| 186 AstNode parent = _variableNode.parent; | 181 AstNode parent = _variableNode.parent; |
| 187 if (parent is VariableDeclarationList) { | 182 if (parent is VariableDeclarationList) { |
| 188 parent = parent.parent; | 183 parent = parent.parent; |
| 189 if (parent is VariableDeclarationStatement) { | 184 if (parent is VariableDeclarationStatement) { |
| 190 parent = parent.parent; | 185 parent = parent.parent; |
| 191 return parent is Block || parent is SwitchCase; | 186 return parent is Block || parent is SwitchCase; |
| 192 } | 187 } |
| 193 } | 188 } |
| 194 return false; | 189 return false; |
| 195 } | 190 } |
| 196 | 191 |
| 197 static bool _shouldBeExpressionInterpolation(InterpolationExpression target, | 192 static bool _shouldBeExpressionInterpolation( |
| 198 Expression expression) { | 193 InterpolationExpression target, Expression expression) { |
| 199 TokenType targetType = target.beginToken.type; | 194 TokenType targetType = target.beginToken.type; |
| 200 return targetType == TokenType.STRING_INTERPOLATION_IDENTIFIER && | 195 return targetType == TokenType.STRING_INTERPOLATION_IDENTIFIER && |
| 201 expression is! SimpleIdentifier; | 196 expression is! SimpleIdentifier; |
| 202 } | 197 } |
| 203 | 198 |
| 204 static bool _shouldUseParenthesis(Expression init, AstNode node) { | 199 static bool _shouldUseParenthesis(Expression init, AstNode node) { |
| 205 // check precedence | 200 // check precedence |
| 206 int initPrecedence = getExpressionPrecedence(init); | 201 int initPrecedence = getExpressionPrecedence(init); |
| 207 if (initPrecedence < getExpressionParentPrecedence(node)) { | 202 if (initPrecedence < getExpressionParentPrecedence(node)) { |
| 208 return true; | 203 return true; |
| 209 } | 204 } |
| 210 // special case for '-' | 205 // special case for '-' |
| 211 AstNode parent = node.parent; | 206 AstNode parent = node.parent; |
| 212 if (init is PrefixExpression && parent is PrefixExpression) { | 207 if (init is PrefixExpression && parent is PrefixExpression) { |
| 213 if (parent.operator.type == TokenType.MINUS) { | 208 if (parent.operator.type == TokenType.MINUS) { |
| 214 TokenType initializerOperator = init.operator.type; | 209 TokenType initializerOperator = init.operator.type; |
| 215 if (initializerOperator == TokenType.MINUS || | 210 if (initializerOperator == TokenType.MINUS || |
| 216 initializerOperator == TokenType.MINUS_MINUS) { | 211 initializerOperator == TokenType.MINUS_MINUS) { |
| 217 return true; | 212 return true; |
| 218 } | 213 } |
| 219 } | 214 } |
| 220 } | 215 } |
| 221 // no () is needed | 216 // no () is needed |
| 222 return false; | 217 return false; |
| 223 } | 218 } |
| 224 } | 219 } |
| OLD | NEW |