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 |