Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: pkg/analysis_server/lib/src/services/correction/assist_internal.dart

Issue 2928313002: Update AssistProcessor to use ChangeBuilder (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:collection'; 6 import 'dart:collection';
7 7
8 import 'package:analysis_server/plugin/edit/assist/assist_core.dart'; 8 import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
9 import 'package:analysis_server/plugin/edit/assist/assist_dart.dart'; 9 import 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
10 import 'package:analysis_server/src/protocol_server.dart' hide Element;
11 import 'package:analysis_server/src/services/correction/assist.dart'; 10 import 'package:analysis_server/src/services/correction/assist.dart';
12 import 'package:analysis_server/src/services/correction/flutter_util.dart'; 11 import 'package:analysis_server/src/services/correction/flutter_util.dart';
13 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; 12 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
14 import 'package:analysis_server/src/services/correction/source_buffer.dart';
15 import 'package:analysis_server/src/services/correction/statement_analyzer.dart' ; 13 import 'package:analysis_server/src/services/correction/statement_analyzer.dart' ;
16 import 'package:analysis_server/src/services/correction/util.dart'; 14 import 'package:analysis_server/src/services/correction/util.dart';
17 import 'package:analysis_server/src/services/search/hierarchy.dart'; 15 import 'package:analysis_server/src/services/search/hierarchy.dart';
18 import 'package:analyzer/dart/ast/ast.dart'; 16 import 'package:analyzer/dart/ast/ast.dart';
19 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; 17 import 'package:analyzer/dart/ast/standard_resolution_map.dart';
20 import 'package:analyzer/dart/ast/token.dart'; 18 import 'package:analyzer/dart/ast/token.dart';
21 import 'package:analyzer/dart/ast/visitor.dart'; 19 import 'package:analyzer/dart/ast/visitor.dart';
22 import 'package:analyzer/dart/element/element.dart'; 20 import 'package:analyzer/dart/element/element.dart';
23 import 'package:analyzer/dart/element/type.dart'; 21 import 'package:analyzer/dart/element/type.dart';
24 import 'package:analyzer/src/dart/analysis/driver.dart'; 22 import 'package:analyzer/src/dart/analysis/driver.dart';
25 import 'package:analyzer/src/dart/ast/token.dart'; 23 import 'package:analyzer/src/dart/ast/token.dart';
26 import 'package:analyzer/src/dart/ast/utilities.dart'; 24 import 'package:analyzer/src/dart/ast/utilities.dart';
27 import 'package:analyzer/src/generated/java_core.dart'; 25 import 'package:analyzer/src/generated/java_core.dart';
28 import 'package:analyzer/src/generated/resolver.dart'; 26 import 'package:analyzer/src/generated/resolver.dart';
29 import 'package:analyzer/src/generated/source.dart'; 27 import 'package:analyzer/src/generated/source.dart';
28 import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
29 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dar t';
30 import 'package:analyzer_plugin/utilities/range_factory.dart'; 30 import 'package:analyzer_plugin/utilities/range_factory.dart';
31 import 'package:path/path.dart'; 31 import 'package:path/path.dart';
32 32
33 typedef _SimpleIdentifierVisitor(SimpleIdentifier node); 33 typedef _SimpleIdentifierVisitor(SimpleIdentifier node);
34 34
35 /** 35 /**
36 * The computer for Dart assists. 36 * The computer for Dart assists.
37 */ 37 */
38 class AssistProcessor { 38 class AssistProcessor {
39 /** 39 /**
(...skipping 10 matching lines...) Expand all
50 50
51 LibraryElement unitLibraryElement; 51 LibraryElement unitLibraryElement;
52 String unitLibraryFile; 52 String unitLibraryFile;
53 String unitLibraryFolder; 53 String unitLibraryFolder;
54 54
55 int selectionOffset; 55 int selectionOffset;
56 int selectionLength; 56 int selectionLength;
57 int selectionEnd; 57 int selectionEnd;
58 58
59 final List<Assist> assists = <Assist>[]; 59 final List<Assist> assists = <Assist>[];
60 final Map<String, LinkedEditGroup> linkedPositionGroups = 60
61 <String, LinkedEditGroup>{};
62 Position exitPosition = null; 61 Position exitPosition = null;
63 62
64 CorrectionUtils utils; 63 CorrectionUtils utils;
64
65 AstNode node; 65 AstNode node;
66 66
67 SourceChange change = new SourceChange('<message>');
68
69 TypeProvider _typeProvider; 67 TypeProvider _typeProvider;
70 68
71 AssistProcessor(DartAssistContext dartContext) { 69 AssistProcessor(DartAssistContext dartContext) {
72 driver = dartContext.analysisDriver; 70 driver = dartContext.analysisDriver;
73 // source 71 // source
74 source = dartContext.source; 72 source = dartContext.source;
75 file = dartContext.source.fullName; 73 file = dartContext.source.fullName;
76 fileStamp = _modificationStamp(file); 74 fileStamp = _modificationStamp(file);
77 // unit 75 // unit
78 unit = dartContext.unit; 76 unit = dartContext.unit;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 try { 109 try {
112 utils = new CorrectionUtils(unit); 110 utils = new CorrectionUtils(unit);
113 } catch (e) { 111 } catch (e) {
114 throw new CancelCorrectionException(exception: e); 112 throw new CancelCorrectionException(exception: e);
115 } 113 }
116 114
117 node = new NodeLocator(selectionOffset, selectionEnd).searchWithin(unit); 115 node = new NodeLocator(selectionOffset, selectionEnd).searchWithin(unit);
118 if (node == null) { 116 if (node == null) {
119 return assists; 117 return assists;
120 } 118 }
121 // try to add proposals 119
122 _addProposal_addTypeAnnotation_DeclaredIdentifier(); 120 await _addProposal_addTypeAnnotation_DeclaredIdentifier();
123 _addProposal_addTypeAnnotation_SimpleFormalParameter(); 121 await _addProposal_addTypeAnnotation_SimpleFormalParameter();
124 _addProposal_addTypeAnnotation_VariableDeclaration(); 122 await _addProposal_addTypeAnnotation_VariableDeclaration();
125 _addProposal_assignToLocalVariable(); 123 await _addProposal_assignToLocalVariable();
126 _addProposal_convertIntoFinalField(); 124 await _addProposal_convertIntoFinalField();
127 _addProposal_convertIntoGetter(); 125 await _addProposal_convertIntoGetter();
128 _addProposal_convertDocumentationIntoBlock(); 126 await _addProposal_convertDocumentationIntoBlock();
129 _addProposal_convertDocumentationIntoLine(); 127 await _addProposal_convertDocumentationIntoLine();
130 _addProposal_convertToBlockFunctionBody(); 128 await _addProposal_convertToBlockFunctionBody();
131 _addProposal_convertToExpressionFunctionBody(); 129 await _addProposal_convertToExpressionFunctionBody();
132 _addProposal_convertFlutterChild(); 130 await _addProposal_convertFlutterChild();
133 _addProposal_convertToForIndexLoop(); 131 await _addProposal_convertToForIndexLoop();
134 _addProposal_convertToIsNot_onIs(); 132 await _addProposal_convertToIsNot_onIs();
135 _addProposal_convertToIsNot_onNot(); 133 await _addProposal_convertToIsNot_onNot();
136 _addProposal_convertToIsNotEmpty(); 134 await _addProposal_convertToIsNotEmpty();
137 _addProposal_convertToFieldParameter(); 135 await _addProposal_convertToFieldParameter();
138 _addProposal_convertToNormalParameter(); 136 await _addProposal_convertToNormalParameter();
139 _addProposal_encapsulateField(); 137 await _addProposal_encapsulateField();
140 _addProposal_exchangeOperands(); 138 await _addProposal_exchangeOperands();
141 _addProposal_importAddShow(); 139 await _addProposal_importAddShow();
142 _addProposal_introduceLocalTestedType(); 140 await _addProposal_introduceLocalTestedType();
143 _addProposal_invertIf(); 141 await _addProposal_invertIf();
144 _addProposal_joinIfStatementInner(); 142 await _addProposal_joinIfStatementInner();
145 _addProposal_joinIfStatementOuter(); 143 await _addProposal_joinIfStatementOuter();
146 _addProposal_joinVariableDeclaration_onAssignment(); 144 await _addProposal_joinVariableDeclaration_onAssignment();
147 _addProposal_joinVariableDeclaration_onDeclaration(); 145 await _addProposal_joinVariableDeclaration_onDeclaration();
148 _addProposal_moveFlutterWidgetDown(); 146 await _addProposal_moveFlutterWidgetDown();
149 _addProposal_moveFlutterWidgetUp(); 147 await _addProposal_moveFlutterWidgetUp();
150 _addProposal_removeTypeAnnotation(); 148 await _addProposal_removeTypeAnnotation();
151 _addProposal_reparentFlutterList(); 149 await _addProposal_reparentFlutterList();
152 _addProposal_reparentFlutterWidget(); 150 await _addProposal_reparentFlutterWidget();
153 _addProposal_replaceConditionalWithIfElse(); 151 await _addProposal_replaceConditionalWithIfElse();
154 _addProposal_replaceIfElseWithConditional(); 152 await _addProposal_replaceIfElseWithConditional();
155 _addProposal_splitAndCondition(); 153 await _addProposal_splitAndCondition();
156 _addProposal_splitVariableDeclaration(); 154 await _addProposal_splitVariableDeclaration();
157 _addProposal_surroundWith(); 155 await _addProposal_surroundWith();
158 // done 156
159 return assists; 157 return assists;
160 } 158 }
161 159
162 FunctionBody getEnclosingFunctionBody() { 160 FunctionBody getEnclosingFunctionBody() {
163 { 161 {
164 FunctionExpression function = 162 FunctionExpression function =
165 node.getAncestor((node) => node is FunctionExpression); 163 node.getAncestor((node) => node is FunctionExpression);
166 if (function != null) { 164 if (function != null) {
167 return function.body; 165 return function.body;
168 } 166 }
(...skipping 15 matching lines...) Expand all
184 { 182 {
185 MethodDeclaration method = 183 MethodDeclaration method =
186 node.getAncestor((node) => node is MethodDeclaration); 184 node.getAncestor((node) => node is MethodDeclaration);
187 if (method != null) { 185 if (method != null) {
188 return method.body; 186 return method.body;
189 } 187 }
190 } 188 }
191 return null; 189 return null;
192 } 190 }
193 191
194 void _addAssist(AssistKind kind, List args, {String assistFile}) { 192 void _addAssistFromBuilder(DartChangeBuilder builder, AssistKind kind,
195 if (assistFile == null) { 193 {List args: null}) {
196 assistFile = file; 194 SourceChange change = builder.sourceChange;
197 }
198 // check is there are any edits
199 if (change.edits.isEmpty) { 195 if (change.edits.isEmpty) {
200 _coverageMarker(); 196 _coverageMarker();
201 return; 197 return;
202 } 198 }
203 // prepare Change
204 change.message = formatList(kind.message, args); 199 change.message = formatList(kind.message, args);
205 linkedPositionGroups.values 200 assists.add(new Assist(kind, change));
206 .forEach((group) => change.addLinkedEditGroup(group));
207 change.selection = exitPosition;
208 // add Assist
209 Assist assist = new Assist(kind, change);
210 assists.add(assist);
211 // clear
212 change = new SourceChange('<message>');
213 linkedPositionGroups.clear();
214 exitPosition = null;
215 } 201 }
216 202
217 void _addIndentEdit(SourceRange range, String oldIndent, String newIndent) { 203 Future<Null> _addProposal_addTypeAnnotation_DeclaredIdentifier() async {
218 SourceEdit edit = utils.createIndentEdit(range, oldIndent, newIndent);
219 doSourceChange_addElementEdit(change, unitElement, edit);
220 }
221
222 /**
223 * Adds a new [Edit] to [edits].
224 */
225 void _addInsertEdit(int offset, String text) {
226 SourceEdit edit = new SourceEdit(offset, 0, text);
227 doSourceChange_addElementEdit(change, unitElement, edit);
228 }
229
230 void _addProposal_addTypeAnnotation_DeclaredIdentifier() {
231 DeclaredIdentifier declaredIdentifier = 204 DeclaredIdentifier declaredIdentifier =
232 node.getAncestor((n) => n is DeclaredIdentifier); 205 node.getAncestor((n) => n is DeclaredIdentifier);
233 if (declaredIdentifier == null) { 206 if (declaredIdentifier == null) {
234 ForEachStatement forEach = node.getAncestor((n) => n is ForEachStatement); 207 ForEachStatement forEach = node.getAncestor((n) => n is ForEachStatement);
235 int offset = node.offset; 208 int offset = node.offset;
236 if (forEach != null && 209 if (forEach != null &&
237 forEach.iterable != null && 210 forEach.iterable != null &&
238 offset < forEach.iterable.offset) { 211 offset < forEach.iterable.offset) {
239 declaredIdentifier = forEach.loopVariable; 212 declaredIdentifier = forEach.loopVariable;
240 } 213 }
241 } 214 }
242 if (declaredIdentifier == null) { 215 if (declaredIdentifier == null) {
243 _coverageMarker(); 216 _coverageMarker();
244 return; 217 return;
245 } 218 }
246 // may be has type annotation already 219 // Ensure that there isn't already a type annotation.
247 if (declaredIdentifier.type != null) { 220 if (declaredIdentifier.type != null) {
248 _coverageMarker(); 221 _coverageMarker();
249 return; 222 return;
250 } 223 }
251 // prepare type source
252 String typeSource;
253 DartType type = declaredIdentifier.identifier.bestType; 224 DartType type = declaredIdentifier.identifier.bestType;
254 if (type is InterfaceType || type is FunctionType) { 225 if (type is! InterfaceType && type is! FunctionType) {
255 _configureTargetLocation(node);
256 Set<Source> librariesToImport = new Set<Source>();
257 typeSource = utils.getTypeSource(type, librariesToImport);
258 addLibraryImports(change, unitLibraryElement, librariesToImport);
259 } else {
260 _coverageMarker(); 226 _coverageMarker();
261 return; 227 return;
262 } 228 }
263 // type source might be null, if the type is private 229 _configureTargetLocation(node);
230 Set<Source> librariesToImport = new Set<Source>();
231 String typeSource = utils.getTypeSource(type, librariesToImport);
264 if (typeSource == null) { 232 if (typeSource == null) {
233 // The type source might be null if the type is private.
265 _coverageMarker(); 234 _coverageMarker();
266 return; 235 return;
267 } 236 }
268 // add edit 237
269 Token keyword = declaredIdentifier.keyword; 238 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
270 if (keyword.keyword == Keyword.VAR) { 239 await changeBuilder.addFileEdit(file, fileStamp,
271 _addReplaceEdit(range.token(keyword), typeSource); 240 (DartFileEditBuilder builder) {
272 } else { 241 Token keyword = declaredIdentifier.keyword;
273 _addInsertEdit(declaredIdentifier.identifier.offset, '$typeSource '); 242 if (keyword.keyword == Keyword.VAR) {
274 } 243 builder.addSimpleReplacement(range.token(keyword), typeSource);
275 // add proposal 244 } else {
276 _addAssist(DartAssistKind.ADD_TYPE_ANNOTATION, []); 245 builder.addSimpleInsertion(
246 declaredIdentifier.identifier.offset, '$typeSource ');
247 }
248 builder.importLibraries(librariesToImport);
249 });
250 _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
277 } 251 }
278 252
279 void _addProposal_addTypeAnnotation_SimpleFormalParameter() { 253 Future<Null> _addProposal_addTypeAnnotation_SimpleFormalParameter() async {
280 AstNode node = this.node; 254 AstNode node = this.node;
281 // should be the name of a simple parameter 255 // should be the name of a simple parameter
282 if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) { 256 if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
283 _coverageMarker(); 257 _coverageMarker();
284 return; 258 return;
285 } 259 }
286 SimpleIdentifier name = node; 260 SimpleIdentifier name = node;
287 SimpleFormalParameter parameter = node.parent; 261 SimpleFormalParameter parameter = node.parent;
288 // the parameter should not have a type 262 // the parameter should not have a type
289 if (parameter.type != null) { 263 if (parameter.type != null) {
290 _coverageMarker(); 264 _coverageMarker();
291 return; 265 return;
292 } 266 }
293 // prepare the type 267 // prepare the type
294 DartType type = parameter.element.type; 268 DartType type = parameter.element.type;
295 // TODO(scheglov) If the parameter is in a method declaration, and if the 269 // TODO(scheglov) If the parameter is in a method declaration, and if the
296 // method overrides a method that has a type for the corresponding 270 // method overrides a method that has a type for the corresponding
297 // parameter, it would be nice to copy down the type from the overridden 271 // parameter, it would be nice to copy down the type from the overridden
298 // method. 272 // method.
299 if (type is! InterfaceType) { 273 if (type is! InterfaceType) {
300 _coverageMarker(); 274 _coverageMarker();
301 return; 275 return;
302 } 276 }
303 // prepare type source 277 // prepare type source
304 String typeSource; 278 _configureTargetLocation(node);
305 { 279 Set<Source> librariesToImport = new Set<Source>();
306 _configureTargetLocation(node); 280 String typeSource = utils.getTypeSource(type, librariesToImport);
307 Set<Source> librariesToImport = new Set<Source>();
308 typeSource = utils.getTypeSource(type, librariesToImport);
309 addLibraryImports(change, unitLibraryElement, librariesToImport);
310 }
311 // type source might be null, if the type is private 281 // type source might be null, if the type is private
312 if (typeSource == null) { 282 if (typeSource == null) {
313 _coverageMarker(); 283 _coverageMarker();
314 return; 284 return;
315 } 285 }
316 // add edit 286
317 _addInsertEdit(name.offset, '$typeSource '); 287 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
318 // add proposal 288 await changeBuilder.addFileEdit(file, fileStamp,
319 _addAssist(DartAssistKind.ADD_TYPE_ANNOTATION, []); 289 (DartFileEditBuilder builder) {
290 builder.addSimpleInsertion(name.offset, '$typeSource ');
291 builder.importLibraries(librariesToImport);
292 });
293 _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
320 } 294 }
321 295
322 void _addProposal_addTypeAnnotation_VariableDeclaration() { 296 Future<Null> _addProposal_addTypeAnnotation_VariableDeclaration() async {
323 AstNode node = this.node; 297 AstNode node = this.node;
324 // prepare VariableDeclarationList 298 // prepare VariableDeclarationList
325 VariableDeclarationList declarationList = 299 VariableDeclarationList declarationList =
326 node.getAncestor((node) => node is VariableDeclarationList); 300 node.getAncestor((node) => node is VariableDeclarationList);
327 if (declarationList == null) { 301 if (declarationList == null) {
328 _coverageMarker(); 302 _coverageMarker();
329 return; 303 return;
330 } 304 }
331 // may be has type annotation already 305 // may be has type annotation already
332 if (declarationList.type != null) { 306 if (declarationList.type != null) {
(...skipping 13 matching lines...) Expand all
346 return; 320 return;
347 } 321 }
348 // we need an initializer to get the type from 322 // we need an initializer to get the type from
349 Expression initializer = variable.initializer; 323 Expression initializer = variable.initializer;
350 if (initializer == null) { 324 if (initializer == null) {
351 _coverageMarker(); 325 _coverageMarker();
352 return; 326 return;
353 } 327 }
354 DartType type = initializer.bestType; 328 DartType type = initializer.bestType;
355 // prepare type source 329 // prepare type source
356 String typeSource; 330 if ((type is! InterfaceType || type.isDartCoreNull) &&
357 if (type is InterfaceType && !type.isDartCoreNull || type is FunctionType) { 331 type is! FunctionType) {
358 _configureTargetLocation(node);
359 Set<Source> librariesToImport = new Set<Source>();
360 typeSource = utils.getTypeSource(type, librariesToImport);
361 addLibraryImports(change, unitLibraryElement, librariesToImport);
362 } else {
363 _coverageMarker(); 332 _coverageMarker();
364 return; 333 return;
365 } 334 }
335 _configureTargetLocation(node);
336 Set<Source> librariesToImport = new Set<Source>();
337 String typeSource = utils.getTypeSource(type, librariesToImport);
366 // type source might be null, if the type is private 338 // type source might be null, if the type is private
367 if (typeSource == null) { 339 if (typeSource == null) {
368 _coverageMarker(); 340 _coverageMarker();
369 return; 341 return;
370 } 342 }
371 // add edit 343
372 Token keyword = declarationList.keyword; 344 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
373 if (keyword?.keyword == Keyword.VAR) { 345 if (unitLibraryFile == file) {
374 _addReplaceEdit(range.token(keyword), typeSource); 346 // TODO(brianwilkerson) Make ChangeBuilder merge multiple edits to the
347 // same file so that only the else block is necessary.
348 await changeBuilder.addFileEdit(file, fileStamp,
349 (DartFileEditBuilder builder) {
350 Token keyword = declarationList.keyword;
351 if (keyword?.keyword == Keyword.VAR) {
352 builder.addSimpleReplacement(range.token(keyword), typeSource);
353 } else {
354 builder.addSimpleInsertion(variable.offset, '$typeSource ');
355 }
356 builder.importLibraries(librariesToImport);
357 });
375 } else { 358 } else {
376 _addInsertEdit(variable.offset, '$typeSource '); 359 await changeBuilder.addFileEdit(file, fileStamp,
360 (DartFileEditBuilder builder) {
361 Token keyword = declarationList.keyword;
362 if (keyword?.keyword == Keyword.VAR) {
363 builder.addSimpleReplacement(range.token(keyword), typeSource);
364 } else {
365 builder.addSimpleInsertion(variable.offset, '$typeSource ');
366 }
367 });
368 await changeBuilder
369 .addFileEdit(unitLibraryFile, _modificationStamp(unitLibraryFile),
370 (DartFileEditBuilder builder) {
371 builder.importLibraries(librariesToImport);
372 });
377 } 373 }
378 // add proposal 374 _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
379 _addAssist(DartAssistKind.ADD_TYPE_ANNOTATION, []);
380 } 375 }
381 376
382 void _addProposal_assignToLocalVariable() { 377 Future<Null> _addProposal_assignToLocalVariable() async {
383 // prepare enclosing ExpressionStatement 378 // prepare enclosing ExpressionStatement
384 ExpressionStatement expressionStatement; 379 ExpressionStatement expressionStatement;
385 for (AstNode node = this.node; node != null; node = node.parent) { 380 for (AstNode node = this.node; node != null; node = node.parent) {
386 if (node is ExpressionStatement) { 381 if (node is ExpressionStatement) {
387 expressionStatement = node; 382 expressionStatement = node;
388 break; 383 break;
389 } 384 }
390 if (node is ArgumentList || 385 if (node is ArgumentList ||
391 node is AssignmentExpression || 386 node is AssignmentExpression ||
392 node is Statement || 387 node is Statement ||
393 node is ThrowExpression) { 388 node is ThrowExpression) {
394 _coverageMarker(); 389 _coverageMarker();
395 return; 390 return;
396 } 391 }
397 } 392 }
398 if (expressionStatement == null) { 393 if (expressionStatement == null) {
399 _coverageMarker(); 394 _coverageMarker();
400 return; 395 return;
401 } 396 }
402 // prepare expression 397 // prepare expression
403 Expression expression = expressionStatement.expression; 398 Expression expression = expressionStatement.expression;
404 int offset = expression.offset; 399 int offset = expression.offset;
405 // prepare expression type 400 // prepare expression type
406 DartType type = expression.bestType; 401 DartType type = expression.bestType;
407 if (type.isVoid) { 402 if (type.isVoid) {
408 _coverageMarker(); 403 _coverageMarker();
409 return; 404 return;
410 } 405 }
411 // prepare source
412 SourceBuilder builder = new SourceBuilder(file, offset);
413 builder.append('var ');
414 // prepare excluded names 406 // prepare excluded names
415 Set<String> excluded = new Set<String>(); 407 Set<String> excluded = new Set<String>();
416 { 408 ScopedNameFinder scopedNameFinder = new ScopedNameFinder(offset);
417 ScopedNameFinder scopedNameFinder = new ScopedNameFinder(offset); 409 expression.accept(scopedNameFinder);
418 expression.accept(scopedNameFinder); 410 excluded.addAll(scopedNameFinder.locals.keys.toSet());
419 excluded.addAll(scopedNameFinder.locals.keys.toSet()); 411 List<String> suggestions =
412 getVariableNameSuggestionsForExpression(type, expression, excluded);
413
414 if (suggestions.isNotEmpty) {
415 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
416 await changeBuilder.addFileEdit(file, fileStamp,
417 (DartFileEditBuilder builder) {
418 builder.addInsertion(offset, (DartEditBuilder builder) {
419 builder.write('var ');
420 builder.addSimpleLinkedEdit('NAME', suggestions[0],
421 kind: LinkedEditSuggestionKind.VARIABLE,
422 suggestions: suggestions);
423 builder.write(' = ');
424 });
425 });
426 _addAssistFromBuilder(
427 changeBuilder, DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
420 } 428 }
421 // name(s)
422 {
423 List<String> suggestions =
424 getVariableNameSuggestionsForExpression(type, expression, excluded);
425 builder.startPosition('NAME');
426 for (int i = 0; i < suggestions.length; i++) {
427 String name = suggestions[i];
428 if (i == 0) {
429 builder.append(name);
430 }
431 builder.addSuggestion(LinkedEditSuggestionKind.VARIABLE, name);
432 }
433 builder.endPosition();
434 }
435 builder.append(' = ');
436 // add proposal
437 _insertBuilder(builder);
438 _addAssist(DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE, []);
439 } 429 }
440 430
441 void _addProposal_convertDocumentationIntoBlock() { 431 Future<Null> _addProposal_convertDocumentationIntoBlock() async {
442 Comment comment = node.getAncestor((n) => n is Comment); 432 Comment comment = node.getAncestor((n) => n is Comment);
443 if (comment != null && comment.isDocumentation) { 433 if (comment == null || !comment.isDocumentation) {
444 String prefix = utils.getNodePrefix(comment); 434 return;
445 SourceBuilder sb = new SourceBuilder(file, comment.offset); 435 }
446 sb.append('/**'); 436 var tokens = comment.tokens;
447 sb.append(eol); 437 if (tokens.isEmpty ||
448 for (Token token in comment.tokens) { 438 tokens.any((Token token) =>
449 if (token is DocumentationCommentToken && 439 token is! DocumentationCommentToken ||
450 token.type == TokenType.SINGLE_LINE_COMMENT) { 440 token.type != TokenType.SINGLE_LINE_COMMENT)) {
451 sb.append(prefix); 441 return;
452 sb.append(' *'); 442 }
453 sb.append(token.lexeme.substring('///'.length)); 443 String prefix = utils.getNodePrefix(comment);
454 sb.append(eol); 444
455 } else { 445 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
446 await changeBuilder.addFileEdit(file, fileStamp,
447 (DartFileEditBuilder builder) {
448 builder.addReplacement(range.node(comment), (DartEditBuilder builder) {
449 builder.writeln('/**');
450 for (Token token in comment.tokens) {
451 builder.write(prefix);
452 builder.write(' *');
453 builder.writeln(token.lexeme.substring('///'.length));
454 }
455 builder.write(prefix);
456 builder.write(' */');
457 });
458 });
459 _addAssistFromBuilder(
460 changeBuilder, DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK);
461 }
462
463 Future<Null> _addProposal_convertDocumentationIntoLine() async {
464 Comment comment = node.getAncestor((n) => n is Comment);
465 if (comment == null ||
466 !comment.isDocumentation ||
467 comment.tokens.length != 1) {
468 _coverageMarker();
469 return;
470 }
471 Token token = comment.tokens.first;
472 if (token.type != TokenType.MULTI_LINE_COMMENT) {
473 _coverageMarker();
474 return;
475 }
476 String text = token.lexeme;
477 List<String> lines = text.split('\n');
478 String prefix = utils.getNodePrefix(comment);
479 List<String> newLines = <String>[];
480 bool firstLine = true;
481 String linePrefix = '';
482 for (String line in lines) {
483 if (firstLine) {
484 firstLine = false;
485 String expectedPrefix = '/**';
486 if (!line.startsWith(expectedPrefix)) {
487 _coverageMarker();
456 return; 488 return;
457 } 489 }
490 line = line.substring(expectedPrefix.length).trim();
491 if (line.isNotEmpty) {
492 newLines.add('/// $line');
493 linePrefix = eol + prefix;
494 }
495 } else {
496 if (line.startsWith(prefix + ' */')) {
497 break;
498 }
499 String expectedPrefix = prefix + ' * ';
500 if (!line.startsWith(expectedPrefix)) {
501 _coverageMarker();
502 return;
503 }
504 line = line.substring(expectedPrefix.length).trim();
505 newLines.add('$linePrefix/// $line');
506 linePrefix = eol + prefix;
458 } 507 }
459 sb.append(prefix);
460 sb.append(' */');
461 _insertBuilder(sb, comment.length);
462 } 508 }
463 // add proposal 509
464 _addAssist(DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK, []); 510 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
511 await changeBuilder.addFileEdit(file, fileStamp,
512 (DartFileEditBuilder builder) {
513 builder.addReplacement(range.node(comment), (DartEditBuilder builder) {
514 for (String newLine in newLines) {
515 builder.write(newLine);
516 }
517 });
518 });
519 _addAssistFromBuilder(
520 changeBuilder, DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE);
465 } 521 }
466 522
467 void _addProposal_convertDocumentationIntoLine() { 523 Future<Null> _addProposal_convertFlutterChild() async {
468 Comment comment = node.getAncestor((n) => n is Comment);
469 if (comment != null && comment.isDocumentation) {
470 if (comment.tokens.length == 1) {
471 Token token = comment.tokens.first;
472 if (token.type == TokenType.MULTI_LINE_COMMENT) {
473 String text = token.lexeme;
474 List<String> lines = text.split('\n');
475 String prefix = utils.getNodePrefix(comment);
476 SourceBuilder sb = new SourceBuilder(file, comment.offset);
477 bool firstLine = true;
478 String linePrefix = '';
479 for (String line in lines) {
480 if (firstLine) {
481 firstLine = false;
482 String expectedPrefix = '/**';
483 if (!line.startsWith(expectedPrefix)) {
484 return;
485 }
486 line = line.substring(expectedPrefix.length).trim();
487 if (line.isNotEmpty) {
488 sb.append('/// ');
489 sb.append(line);
490 linePrefix = eol + prefix;
491 }
492 } else {
493 if (line.startsWith(prefix + ' */')) {
494 break;
495 }
496 String expectedPrefix = prefix + ' * ';
497 if (!line.startsWith(expectedPrefix)) {
498 return;
499 }
500 line = line.substring(expectedPrefix.length).trim();
501 sb.append(linePrefix);
502 sb.append('/// ');
503 sb.append(line);
504 linePrefix = eol + prefix;
505 }
506 }
507 _insertBuilder(sb, comment.length);
508 }
509 }
510 }
511 // add proposal
512 _addAssist(DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE, []);
513 }
514
515 void _addProposal_convertFlutterChild() {
516 NamedExpression namedExp; 524 NamedExpression namedExp;
517 // Allow assist to activate from either the new-expr or the child: arg. 525 // Allow assist to activate from either the new-expr or the child: arg.
518 if (node is SimpleIdentifier && 526 if (node is SimpleIdentifier &&
519 node.parent is Label && 527 node.parent is Label &&
520 node.parent.parent is NamedExpression) { 528 node.parent.parent is NamedExpression) {
521 namedExp = node.parent.parent as NamedExpression; 529 namedExp = node.parent.parent as NamedExpression;
522 if ((node as SimpleIdentifier).name != 'child' || 530 if ((node as SimpleIdentifier).name != 'child' ||
523 namedExp.expression == null) { 531 namedExp.expression == null) {
524 return; 532 return;
525 } 533 }
(...skipping 14 matching lines...) Expand all
540 if (namedExp == null || namedExp.expression == null) { 548 if (namedExp == null || namedExp.expression == null) {
541 _coverageMarker(); 549 _coverageMarker();
542 return; 550 return;
543 } 551 }
544 } 552 }
545 InstanceCreationExpression childArg = getChildWidget(namedExp, false); 553 InstanceCreationExpression childArg = getChildWidget(namedExp, false);
546 if (childArg == null) { 554 if (childArg == null) {
547 _coverageMarker(); 555 _coverageMarker();
548 return; 556 return;
549 } 557 }
550 convertFlutterChildToChildren( 558 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
551 childArg, 559 await changeBuilder.addFileEdit(file, fileStamp,
552 namedExp, 560 (DartFileEditBuilder builder) {
553 eol, 561 _convertFlutterChildToChildren(childArg, namedExp, eol, utils.getNodeText,
554 utils.getNodeText, 562 utils.getLinePrefix, utils.getIndent, utils.getText, builder);
555 utils.getLinePrefix, 563 });
556 utils.getIndent, 564 _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_FLUTTER_CHILD);
557 utils.getText,
558 _addInsertEdit,
559 _addRemoveEdit,
560 _addReplaceEdit,
561 range.node);
562 _addAssist(DartAssistKind.CONVERT_FLUTTER_CHILD, []);
563 } 565 }
564 566
565 void _addProposal_convertIntoFinalField() { 567 Future<Null> _addProposal_convertIntoFinalField() async {
566 // Find the enclosing getter. 568 // Find the enclosing getter.
567 MethodDeclaration getter; 569 MethodDeclaration getter;
568 for (AstNode n = node; n != null; n = n.parent) { 570 for (AstNode n = node; n != null; n = n.parent) {
569 if (n is MethodDeclaration) { 571 if (n is MethodDeclaration) {
570 getter = n; 572 getter = n;
571 break; 573 break;
572 } 574 }
573 if (n is SimpleIdentifier || 575 if (n is SimpleIdentifier ||
574 n is TypeAnnotation || 576 n is TypeAnnotation ||
575 n is TypeArgumentList) { 577 n is TypeArgumentList) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 String code = 'final'; 617 String code = 'final';
616 if (getter.returnType != null) { 618 if (getter.returnType != null) {
617 beginNodeToReplace = getter.returnType; 619 beginNodeToReplace = getter.returnType;
618 code += ' ' + _getNodeText(getter.returnType); 620 code += ' ' + _getNodeText(getter.returnType);
619 } 621 }
620 code += ' ' + _getNodeText(getter.name); 622 code += ' ' + _getNodeText(getter.name);
621 if (expression is! NullLiteral) { 623 if (expression is! NullLiteral) {
622 code += ' = ' + _getNodeText(expression); 624 code += ' = ' + _getNodeText(expression);
623 } 625 }
624 code += ';'; 626 code += ';';
625 _addReplaceEdit(range.startEnd(beginNodeToReplace, getter), code); 627 SourceRange replacementRange = range.startEnd(beginNodeToReplace, getter);
626 _addAssist(DartAssistKind.CONVERT_INTO_FINAL_FIELD, []); 628 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
629 await changeBuilder.addFileEdit(file, fileStamp,
630 (DartFileEditBuilder builder) {
631 builder.addSimpleReplacement(replacementRange, code);
632 });
633 _addAssistFromBuilder(
634 changeBuilder, DartAssistKind.CONVERT_INTO_FINAL_FIELD);
627 } 635 }
628 } 636 }
629 637
630 void _addProposal_convertIntoGetter() { 638 Future<Null> _addProposal_convertIntoGetter() async {
631 // Find the enclosing field declaration. 639 // Find the enclosing field declaration.
632 FieldDeclaration fieldDeclaration; 640 FieldDeclaration fieldDeclaration;
633 for (AstNode n = node; n != null; n = n.parent) { 641 for (AstNode n = node; n != null; n = n.parent) {
634 if (n is FieldDeclaration) { 642 if (n is FieldDeclaration) {
635 fieldDeclaration = n; 643 fieldDeclaration = n;
636 break; 644 break;
637 } 645 }
638 if (n is SimpleIdentifier || 646 if (n is SimpleIdentifier ||
639 n is VariableDeclaration || 647 n is VariableDeclaration ||
640 n is VariableDeclarationList || 648 n is VariableDeclarationList ||
(...skipping 19 matching lines...) Expand all
660 } 668 }
661 // Add proposal. 669 // Add proposal.
662 String code = ''; 670 String code = '';
663 if (fieldList.type != null) { 671 if (fieldList.type != null) {
664 code += _getNodeText(fieldList.type) + ' '; 672 code += _getNodeText(fieldList.type) + ' ';
665 } 673 }
666 code += 'get'; 674 code += 'get';
667 code += ' ' + _getNodeText(field.name); 675 code += ' ' + _getNodeText(field.name);
668 code += ' => ' + _getNodeText(initializer); 676 code += ' => ' + _getNodeText(initializer);
669 code += ';'; 677 code += ';';
670 _addReplaceEdit(range.startEnd(fieldList.keyword, fieldDeclaration), code); 678 SourceRange replacementRange =
671 _addAssist(DartAssistKind.CONVERT_INTO_GETTER, []); 679 range.startEnd(fieldList.keyword, fieldDeclaration);
680 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
681 await changeBuilder.addFileEdit(file, fileStamp,
682 (DartFileEditBuilder builder) {
683 builder.addSimpleReplacement(replacementRange, code);
684 });
685 _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_INTO_GETTER);
672 } 686 }
673 687
674 void _addProposal_convertToBlockFunctionBody() { 688 Future<Null> _addProposal_convertToBlockFunctionBody() async {
675 FunctionBody body = getEnclosingFunctionBody(); 689 FunctionBody body = getEnclosingFunctionBody();
676 // prepare expression body 690 // prepare expression body
677 if (body is! ExpressionFunctionBody || body.isGenerator) { 691 if (body is! ExpressionFunctionBody || body.isGenerator) {
678 _coverageMarker(); 692 _coverageMarker();
679 return; 693 return;
680 } 694 }
681 Expression returnValue = (body as ExpressionFunctionBody).expression; 695 Expression returnValue = (body as ExpressionFunctionBody).expression;
682 DartType returnValueType = returnValue.staticType; 696 DartType returnValueType = returnValue.staticType;
683 String returnValueCode = _getNodeText(returnValue); 697 String returnValueCode = _getNodeText(returnValue);
684 // prepare prefix 698 // prepare prefix
685 String prefix = utils.getNodePrefix(body.parent); 699 String prefix = utils.getNodePrefix(body.parent);
686 String indent = utils.getIndent(1); 700 String indent = utils.getIndent(1);
687 // add change 701
688 SourceBuilder sb = new SourceBuilder(file, body.offset); 702 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
689 if (body.isAsynchronous) { 703 await changeBuilder.addFileEdit(file, fileStamp,
690 sb.append('async '); 704 (DartFileEditBuilder builder) {
691 } 705 builder.addReplacement(range.node(body), (DartEditBuilder builder) {
692 sb.append('{$eol$prefix$indent'); 706 if (body.isAsynchronous) {
693 if (!returnValueType.isVoid) { 707 builder.write('async ');
694 sb.append('return '); 708 }
695 } 709 builder.write('{$eol$prefix$indent');
696 sb.append(returnValueCode); 710 if (!returnValueType.isVoid) {
697 sb.append(';'); 711 builder.write('return ');
698 sb.setExitOffset(); 712 }
699 sb.append('$eol$prefix}'); 713 builder.write(returnValueCode);
700 _insertBuilder(sb, body.length); 714 builder.write(';');
701 // add proposal 715 builder.selectHere();
702 _addAssist(DartAssistKind.CONVERT_INTO_BLOCK_BODY, []); 716 builder.write('$eol$prefix}');
717 });
718 });
719 _addAssistFromBuilder(
720 changeBuilder, DartAssistKind.CONVERT_INTO_BLOCK_BODY);
703 } 721 }
704 722
705 void _addProposal_convertToExpressionFunctionBody() { 723 Future<Null> _addProposal_convertToExpressionFunctionBody() async {
706 // prepare current body 724 // prepare current body
707 FunctionBody body = getEnclosingFunctionBody(); 725 FunctionBody body = getEnclosingFunctionBody();
708 if (body is! BlockFunctionBody || body.isGenerator) { 726 if (body is! BlockFunctionBody || body.isGenerator) {
709 _coverageMarker(); 727 _coverageMarker();
710 return; 728 return;
711 } 729 }
712 // prepare return statement 730 // prepare return statement
713 List<Statement> statements = (body as BlockFunctionBody).block.statements; 731 List<Statement> statements = (body as BlockFunctionBody).block.statements;
714 if (statements.length != 1) { 732 if (statements.length != 1) {
715 _coverageMarker(); 733 _coverageMarker();
716 return; 734 return;
717 } 735 }
718 Statement onlyStatement = statements.first; 736 Statement onlyStatement = statements.first;
719 // prepare returned expression 737 // prepare returned expression
720 Expression returnExpression; 738 Expression returnExpression;
721 if (onlyStatement is ReturnStatement) { 739 if (onlyStatement is ReturnStatement) {
722 returnExpression = onlyStatement.expression; 740 returnExpression = onlyStatement.expression;
723 } else if (onlyStatement is ExpressionStatement) { 741 } else if (onlyStatement is ExpressionStatement) {
724 returnExpression = onlyStatement.expression; 742 returnExpression = onlyStatement.expression;
725 } 743 }
726 if (returnExpression == null) { 744 if (returnExpression == null) {
727 _coverageMarker(); 745 _coverageMarker();
728 return; 746 return;
729 } 747 }
730 // add change 748
731 SourceBuilder sb = new SourceBuilder(file, body.offset); 749 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
732 if (body.isAsynchronous) { 750 await changeBuilder.addFileEdit(file, fileStamp,
733 sb.append('async '); 751 (DartFileEditBuilder builder) {
734 } 752 builder.addReplacement(range.node(body), (DartEditBuilder builder) {
735 sb.append('=> '); 753 if (body.isAsynchronous) {
736 sb.append(_getNodeText(returnExpression)); 754 builder.write('async ');
737 if (body.parent is! FunctionExpression || 755 }
738 body.parent.parent is FunctionDeclaration) { 756 builder.write('=> ');
739 sb.append(';'); 757 builder.write(_getNodeText(returnExpression));
740 } 758 if (body.parent is! FunctionExpression ||
741 _insertBuilder(sb, body.length); 759 body.parent.parent is FunctionDeclaration) {
742 // add proposal 760 builder.write(';');
743 _addAssist(DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, []); 761 }
762 });
763 });
764 _addAssistFromBuilder(
765 changeBuilder, DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
744 } 766 }
745 767
746 void _addProposal_convertToFieldParameter() { 768 Future<Null> _addProposal_convertToFieldParameter() async {
747 if (node == null) { 769 if (node == null) {
748 return; 770 return;
749 } 771 }
750 // prepare ConstructorDeclaration 772 // prepare ConstructorDeclaration
751 ConstructorDeclaration constructor = 773 ConstructorDeclaration constructor =
752 node.getAncestor((node) => node is ConstructorDeclaration); 774 node.getAncestor((node) => node is ConstructorDeclaration);
753 if (constructor == null) { 775 if (constructor == null) {
754 return; 776 return;
755 } 777 }
756 FormalParameterList parameterList = constructor.parameters; 778 FormalParameterList parameterList = constructor.parameters;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
803 if (expression is SimpleIdentifier && 825 if (expression is SimpleIdentifier &&
804 expression.name == parameterName) { 826 expression.name == parameterName) {
805 parameterInitializer = initializer; 827 parameterInitializer = initializer;
806 } 828 }
807 } 829 }
808 } 830 }
809 if (parameterInitializer == null) { 831 if (parameterInitializer == null) {
810 return; 832 return;
811 } 833 }
812 String fieldName = parameterInitializer.fieldName.name; 834 String fieldName = parameterInitializer.fieldName.name;
813 // replace parameter 835
814 _addReplaceEdit(range.node(parameter), 'this.$fieldName'); 836 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
815 // remove initializer 837 await changeBuilder.addFileEdit(file, fileStamp,
816 int initializerIndex = initializers.indexOf(parameterInitializer); 838 (DartFileEditBuilder builder) {
817 if (initializers.length == 1) { 839 // replace parameter
818 _addRemoveEdit(range.endEnd(parameterList, parameterInitializer)); 840 builder.addSimpleReplacement(range.node(parameter), 'this.$fieldName');
819 } else { 841 // remove initializer
820 if (initializerIndex == 0) { 842 int initializerIndex = initializers.indexOf(parameterInitializer);
821 ConstructorInitializer next = initializers[initializerIndex + 1]; 843 if (initializers.length == 1) {
822 _addRemoveEdit(range.startStart(parameterInitializer, next)); 844 builder
845 .addDeletion(range.endEnd(parameterList, parameterInitializer));
823 } else { 846 } else {
824 ConstructorInitializer prev = initializers[initializerIndex - 1]; 847 if (initializerIndex == 0) {
825 _addRemoveEdit(range.endEnd(prev, parameterInitializer)); 848 ConstructorInitializer next = initializers[initializerIndex + 1];
849 builder.addDeletion(range.startStart(parameterInitializer, next));
850 } else {
851 ConstructorInitializer prev = initializers[initializerIndex - 1];
852 builder.addDeletion(range.endEnd(prev, parameterInitializer));
853 }
826 } 854 }
827 } 855 });
828 // add proposal 856 _addAssistFromBuilder(
829 _addAssist(DartAssistKind.CONVERT_TO_FIELD_PARAMETER, []); 857 changeBuilder, DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
830 } 858 }
831 } 859 }
832 860
833 void _addProposal_convertToForIndexLoop() { 861 Future<Null> _addProposal_convertToForIndexLoop() async {
834 // find enclosing ForEachStatement 862 // find enclosing ForEachStatement
835 ForEachStatement forEachStatement = 863 ForEachStatement forEachStatement =
836 node.getAncestor((n) => n is ForEachStatement); 864 node.getAncestor((n) => n is ForEachStatement);
837 if (forEachStatement == null) { 865 if (forEachStatement == null) {
838 _coverageMarker(); 866 _coverageMarker();
839 return; 867 return;
840 } 868 }
841 if (selectionOffset < forEachStatement.offset || 869 if (selectionOffset < forEachStatement.offset ||
842 forEachStatement.rightParenthesis.end < selectionOffset) { 870 forEachStatement.rightParenthesis.end < selectionOffset) {
843 _coverageMarker(); 871 _coverageMarker();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 } else { 917 } else {
890 _coverageMarker(); 918 _coverageMarker();
891 return; 919 return;
892 } 920 }
893 } 921 }
894 // prepare environment 922 // prepare environment
895 String prefix = utils.getNodePrefix(forEachStatement); 923 String prefix = utils.getNodePrefix(forEachStatement);
896 String indent = utils.getIndent(1); 924 String indent = utils.getIndent(1);
897 int firstBlockLine = utils.getLineContentEnd(body.leftBracket.end); 925 int firstBlockLine = utils.getLineContentEnd(body.leftBracket.end);
898 // add change 926 // add change
899 _addReplaceEdit( 927 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
900 range.startEnd(forEachStatement, forEachStatement.rightParenthesis), 928 await changeBuilder.addFileEdit(file, fileStamp,
901 'for (int $indexName = 0; $indexName < $listName.length; $indexName++)') ; 929 (DartFileEditBuilder builder) {
902 _addInsertEdit(firstBlockLine, 930 // TODO(brianwilkerson) Create linked positions for the loop variable.
903 '$prefix$indent$loopVariable = $listName[$indexName];$eol'); 931 builder.addSimpleReplacement(
904 // add proposal 932 range.startEnd(forEachStatement, forEachStatement.rightParenthesis),
905 _addAssist(DartAssistKind.CONVERT_INTO_FOR_INDEX, []); 933 'for (int $indexName = 0; $indexName < $listName.length; $indexName++) ');
934 builder.addSimpleInsertion(firstBlockLine,
935 '$prefix$indent$loopVariable = $listName[$indexName];$eol');
936 });
937 _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_INTO_FOR_INDEX);
906 } 938 }
907 939
908 void _addProposal_convertToIsNot_onIs() { 940 Future<Null> _addProposal_convertToIsNot_onIs() async {
909 // may be child of "is" 941 // may be child of "is"
910 AstNode node = this.node; 942 AstNode node = this.node;
911 while (node != null && node is! IsExpression) { 943 while (node != null && node is! IsExpression) {
912 node = node.parent; 944 node = node.parent;
913 } 945 }
914 // prepare "is" 946 // prepare "is"
915 if (node is! IsExpression) { 947 if (node is! IsExpression) {
916 _coverageMarker(); 948 _coverageMarker();
917 return; 949 return;
918 } 950 }
(...skipping 13 matching lines...) Expand all
932 AstNode parent2 = parent.parent; 964 AstNode parent2 = parent.parent;
933 if (parent2 is! PrefixExpression) { 965 if (parent2 is! PrefixExpression) {
934 _coverageMarker(); 966 _coverageMarker();
935 return; 967 return;
936 } 968 }
937 PrefixExpression prefExpression = parent2 as PrefixExpression; 969 PrefixExpression prefExpression = parent2 as PrefixExpression;
938 if (prefExpression.operator.type != TokenType.BANG) { 970 if (prefExpression.operator.type != TokenType.BANG) {
939 _coverageMarker(); 971 _coverageMarker();
940 return; 972 return;
941 } 973 }
942 // strip !() 974
943 if (getExpressionParentPrecedence(prefExpression) >= 975 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
944 TokenClass.RELATIONAL_OPERATOR.precedence) { 976 await changeBuilder.addFileEdit(file, fileStamp,
945 _addRemoveEdit(range.token(prefExpression.operator)); 977 (DartFileEditBuilder builder) {
946 } else { 978 if (getExpressionParentPrecedence(prefExpression) >=
947 _addRemoveEdit( 979 TokenClass.RELATIONAL_OPERATOR.precedence) {
948 range.startEnd(prefExpression, parExpression.leftParenthesis)); 980 builder.addDeletion(range.token(prefExpression.operator));
949 _addRemoveEdit( 981 } else {
950 range.startEnd(parExpression.rightParenthesis, prefExpression)); 982 builder.addDeletion(
951 } 983 range.startEnd(prefExpression, parExpression.leftParenthesis));
952 _addInsertEdit(isExpression.isOperator.end, '!'); 984 builder.addDeletion(
953 // add proposal 985 range.startEnd(parExpression.rightParenthesis, prefExpression));
954 _addAssist(DartAssistKind.CONVERT_INTO_IS_NOT, []); 986 }
987 builder.addSimpleInsertion(isExpression.isOperator.end, '!');
988 });
989 _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_INTO_IS_NOT);
955 } 990 }
956 991
957 void _addProposal_convertToIsNot_onNot() { 992 Future<Null> _addProposal_convertToIsNot_onNot() async {
958 // may be () in prefix expression 993 // may be () in prefix expression
959 if (node is ParenthesizedExpression && node.parent is PrefixExpression) { 994 if (node is ParenthesizedExpression && node.parent is PrefixExpression) {
960 node = node.parent; 995 node = node.parent;
961 } 996 }
962 // prepare !() 997 // prepare !()
963 if (node is! PrefixExpression) { 998 if (node is! PrefixExpression) {
964 _coverageMarker(); 999 _coverageMarker();
965 return; 1000 return;
966 } 1001 }
967 PrefixExpression prefExpression = node as PrefixExpression; 1002 PrefixExpression prefExpression = node as PrefixExpression;
(...skipping 13 matching lines...) Expand all
981 // prepare "is" 1016 // prepare "is"
982 if (operand is! IsExpression) { 1017 if (operand is! IsExpression) {
983 _coverageMarker(); 1018 _coverageMarker();
984 return; 1019 return;
985 } 1020 }
986 IsExpression isExpression = operand as IsExpression; 1021 IsExpression isExpression = operand as IsExpression;
987 if (isExpression.notOperator != null) { 1022 if (isExpression.notOperator != null) {
988 _coverageMarker(); 1023 _coverageMarker();
989 return; 1024 return;
990 } 1025 }
991 // strip !() 1026
992 if (getExpressionParentPrecedence(prefExpression) >= 1027 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
993 TokenClass.RELATIONAL_OPERATOR.precedence) { 1028 await changeBuilder.addFileEdit(file, fileStamp,
994 _addRemoveEdit(range.token(prefExpression.operator)); 1029 (DartFileEditBuilder builder) {
995 } else { 1030 if (getExpressionParentPrecedence(prefExpression) >=
996 _addRemoveEdit( 1031 TokenClass.RELATIONAL_OPERATOR.precedence) {
997 range.startEnd(prefExpression, parExpression.leftParenthesis)); 1032 builder.addDeletion(range.token(prefExpression.operator));
998 _addRemoveEdit( 1033 } else {
999 range.startEnd(parExpression.rightParenthesis, prefExpression)); 1034 builder.addDeletion(
1000 } 1035 range.startEnd(prefExpression, parExpression.leftParenthesis));
1001 _addInsertEdit(isExpression.isOperator.end, '!'); 1036 builder.addDeletion(
1002 // add proposal 1037 range.startEnd(parExpression.rightParenthesis, prefExpression));
1003 _addAssist(DartAssistKind.CONVERT_INTO_IS_NOT, []); 1038 }
1039 builder.addSimpleInsertion(isExpression.isOperator.end, '!');
1040 });
1041 _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_INTO_IS_NOT);
1004 } 1042 }
1005 1043
1006 /** 1044 /**
1007 * Converts "!isEmpty" -> "isNotEmpty" if possible. 1045 * Converts "!isEmpty" -> "isNotEmpty" if possible.
1008 */ 1046 */
1009 void _addProposal_convertToIsNotEmpty() { 1047 Future<Null> _addProposal_convertToIsNotEmpty() async {
1010 // prepare "expr.isEmpty" 1048 // prepare "expr.isEmpty"
1011 AstNode isEmptyAccess = null; 1049 AstNode isEmptyAccess = null;
1012 SimpleIdentifier isEmptyIdentifier = null; 1050 SimpleIdentifier isEmptyIdentifier = null;
1013 if (node is SimpleIdentifier) { 1051 if (node is SimpleIdentifier) {
1014 SimpleIdentifier identifier = node as SimpleIdentifier; 1052 SimpleIdentifier identifier = node as SimpleIdentifier;
1015 AstNode parent = identifier.parent; 1053 AstNode parent = identifier.parent;
1016 // normal case (but rare) 1054 // normal case (but rare)
1017 if (parent is PropertyAccess) { 1055 if (parent is PropertyAccess) {
1018 isEmptyIdentifier = parent.propertyName; 1056 isEmptyIdentifier = parent.propertyName;
1019 isEmptyAccess = parent; 1057 isEmptyAccess = parent;
(...skipping 26 matching lines...) Expand all
1046 _coverageMarker(); 1084 _coverageMarker();
1047 return; 1085 return;
1048 } 1086 }
1049 PrefixExpression prefixExpression = 1087 PrefixExpression prefixExpression =
1050 isEmptyAccess.parent as PrefixExpression; 1088 isEmptyAccess.parent as PrefixExpression;
1051 // should be ! 1089 // should be !
1052 if (prefixExpression.operator.type != TokenType.BANG) { 1090 if (prefixExpression.operator.type != TokenType.BANG) {
1053 _coverageMarker(); 1091 _coverageMarker();
1054 return; 1092 return;
1055 } 1093 }
1056 // do replace 1094
1057 _addRemoveEdit( 1095 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1058 range.startStart(prefixExpression, prefixExpression.operand)); 1096 await changeBuilder.addFileEdit(file, fileStamp,
1059 _addReplaceEdit(range.node(isEmptyIdentifier), 'isNotEmpty'); 1097 (DartFileEditBuilder builder) {
1060 // add proposal 1098 builder.addDeletion(
1061 _addAssist(DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY, []); 1099 range.startStart(prefixExpression, prefixExpression.operand));
1100 builder.addSimpleReplacement(range.node(isEmptyIdentifier), 'isNotEmpty');
1101 });
1102 _addAssistFromBuilder(
1103 changeBuilder, DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
1062 } 1104 }
1063 1105
1064 void _addProposal_convertToNormalParameter() { 1106 Future<Null> _addProposal_convertToNormalParameter() async {
1065 if (node is SimpleIdentifier && 1107 if (node is SimpleIdentifier &&
1066 node.parent is FieldFormalParameter && 1108 node.parent is FieldFormalParameter &&
1067 node.parent.parent is FormalParameterList && 1109 node.parent.parent is FormalParameterList &&
1068 node.parent.parent.parent is ConstructorDeclaration) { 1110 node.parent.parent.parent is ConstructorDeclaration) {
1069 ConstructorDeclaration constructor = node.parent.parent.parent; 1111 ConstructorDeclaration constructor = node.parent.parent.parent;
1070 FormalParameterList parameterList = node.parent.parent; 1112 FormalParameterList parameterList = node.parent.parent;
1071 FieldFormalParameter parameter = node.parent; 1113 FieldFormalParameter parameter = node.parent;
1072 ParameterElement parameterElement = parameter.element; 1114 ParameterElement parameterElement = parameter.element;
1073 String name = (node as SimpleIdentifier).name; 1115 String name = (node as SimpleIdentifier).name;
1074 // prepare type 1116 // prepare type
1075 DartType type = parameterElement.type; 1117 DartType type = parameterElement.type;
1076 Set<Source> librariesToImport = new Set<Source>(); 1118 Set<Source> librariesToImport = new Set<Source>();
1077 String typeCode = utils.getTypeSource(type, librariesToImport); 1119 String typeCode = utils.getTypeSource(type, librariesToImport);
1078 // replace parameter 1120
1079 if (type.isDynamic) { 1121 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1080 _addReplaceEdit(range.node(parameter), name); 1122 await changeBuilder.addFileEdit(file, fileStamp,
1081 } else { 1123 (DartFileEditBuilder builder) {
1082 _addReplaceEdit(range.node(parameter), '$typeCode $name'); 1124 // replace parameter
1083 } 1125 if (type.isDynamic) {
1084 // add field initializer 1126 builder.addSimpleReplacement(range.node(parameter), name);
1085 List<ConstructorInitializer> initializers = constructor.initializers; 1127 } else {
1086 if (initializers.isEmpty) { 1128 builder.addSimpleReplacement(
1087 _addInsertEdit(parameterList.end, ' : $name = $name'); 1129 range.node(parameter), '$typeCode $name');
1088 } else { 1130 }
1089 _addInsertEdit(initializers.last.end, ', $name = $name'); 1131 // add field initializer
1090 } 1132 List<ConstructorInitializer> initializers = constructor.initializers;
1091 // add proposal 1133 if (initializers.isEmpty) {
1092 _addAssist(DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, []); 1134 builder.addSimpleInsertion(parameterList.end, ' : $name = $name');
1135 } else {
1136 builder.addSimpleInsertion(initializers.last.end, ', $name = $name');
1137 }
1138 });
1139 _addAssistFromBuilder(
1140 changeBuilder, DartAssistKind.CONVERT_TO_NORMAL_PARAMETER);
1093 } 1141 }
1094 } 1142 }
1095 1143
1096 void _addProposal_encapsulateField() { 1144 Future<Null> _addProposal_encapsulateField() async {
1097 // find FieldDeclaration 1145 // find FieldDeclaration
1098 FieldDeclaration fieldDeclaration = 1146 FieldDeclaration fieldDeclaration =
1099 node.getAncestor((x) => x is FieldDeclaration); 1147 node.getAncestor((x) => x is FieldDeclaration);
1100 if (fieldDeclaration == null) { 1148 if (fieldDeclaration == null) {
1101 _coverageMarker(); 1149 _coverageMarker();
1102 return; 1150 return;
1103 } 1151 }
1104 // not interesting for static 1152 // not interesting for static
1105 if (fieldDeclaration.isStatic) { 1153 if (fieldDeclaration.isStatic) {
1106 _coverageMarker(); 1154 _coverageMarker();
(...skipping 23 matching lines...) Expand all
1130 String name = nameNode.name; 1178 String name = nameNode.name;
1131 if (Identifier.isPrivateName(name)) { 1179 if (Identifier.isPrivateName(name)) {
1132 _coverageMarker(); 1180 _coverageMarker();
1133 return; 1181 return;
1134 } 1182 }
1135 // should be on the name 1183 // should be on the name
1136 if (nameNode != node) { 1184 if (nameNode != node) {
1137 _coverageMarker(); 1185 _coverageMarker();
1138 return; 1186 return;
1139 } 1187 }
1140 // rename field 1188 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1141 _addReplaceEdit(range.node(nameNode), '_$name'); 1189 await changeBuilder.addFileEdit(file, fileStamp,
1142 // update references in constructors 1190 (DartFileEditBuilder builder) {
1143 ClassDeclaration classDeclaration = fieldDeclaration.parent; 1191 // rename field
1144 for (ClassMember member in classDeclaration.members) { 1192 builder.addSimpleReplacement(range.node(nameNode), '_$name');
1145 if (member is ConstructorDeclaration) { 1193 // update references in constructors
1146 for (FormalParameter parameter in member.parameters.parameters) { 1194 ClassDeclaration classDeclaration = fieldDeclaration.parent;
1147 ParameterElement parameterElement = parameter.element; 1195 for (ClassMember member in classDeclaration.members) {
1148 if (parameterElement is FieldFormalParameterElement && 1196 if (member is ConstructorDeclaration) {
1149 parameterElement.field == fieldElement) { 1197 for (FormalParameter parameter in member.parameters.parameters) {
1150 _addReplaceEdit(range.node(parameter.identifier), '_$name'); 1198 ParameterElement parameterElement = parameter.element;
1199 if (parameterElement is FieldFormalParameterElement &&
1200 parameterElement.field == fieldElement) {
1201 SimpleIdentifier identifier = parameter.identifier;
1202 builder.addSimpleReplacement(range.node(identifier), '_$name');
1203 }
1151 } 1204 }
1152 } 1205 }
1153 } 1206 }
1154 } 1207 // add accessors
1155 // add accessors 1208 String eol2 = eol + eol;
1156 String eol2 = eol + eol; 1209 String typeNameCode = variableList.type != null
1157 String typeNameCode = 1210 ? _getNodeText(variableList.type) + ' '
1158 variableList.type != null ? _getNodeText(variableList.type) + ' ' : ''; 1211 : '';
1159 String getterCode = '$eol2 ${typeNameCode}get $name => _$name;'; 1212 String getterCode = '$eol2 ${typeNameCode}get $name => _$name;';
1160 String setterCode = '$eol2' 1213 String setterCode = '$eol2'
1161 ' void set $name($typeNameCode$name) {$eol' 1214 ' void set $name($typeNameCode$name) {$eol'
1162 ' _$name = $name;$eol' 1215 ' _$name = $name;$eol'
1163 ' }'; 1216 ' }';
1164 _addInsertEdit(fieldDeclaration.end, getterCode + setterCode); 1217 builder.addSimpleInsertion(fieldDeclaration.end, getterCode + setterCode);
1165 // add proposal 1218 });
1166 _addAssist(DartAssistKind.ENCAPSULATE_FIELD, []); 1219 _addAssistFromBuilder(changeBuilder, DartAssistKind.ENCAPSULATE_FIELD);
1167 } 1220 }
1168 1221
1169 void _addProposal_exchangeOperands() { 1222 Future<Null> _addProposal_exchangeOperands() async {
1170 // check that user invokes quick assist on binary expression 1223 // check that user invokes quick assist on binary expression
1171 if (node is! BinaryExpression) { 1224 if (node is! BinaryExpression) {
1172 _coverageMarker(); 1225 _coverageMarker();
1173 return; 1226 return;
1174 } 1227 }
1175 BinaryExpression binaryExpression = node as BinaryExpression; 1228 BinaryExpression binaryExpression = node as BinaryExpression;
1176 // prepare operator position 1229 // prepare operator position
1177 if (!_isOperatorSelected( 1230 if (!_isOperatorSelected(
1178 binaryExpression, selectionOffset, selectionLength)) { 1231 binaryExpression, selectionOffset, selectionLength)) {
1179 _coverageMarker(); 1232 _coverageMarker();
1180 return; 1233 return;
1181 } 1234 }
1182 // add edits 1235 // add edits
1183 { 1236 Expression leftOperand = binaryExpression.leftOperand;
1184 Expression leftOperand = binaryExpression.leftOperand; 1237 Expression rightOperand = binaryExpression.rightOperand;
1185 Expression rightOperand = binaryExpression.rightOperand; 1238 // find "wide" enclosing binary expression with same operator
1186 // find "wide" enclosing binary expression with same operator 1239 while (binaryExpression.parent is BinaryExpression) {
1187 while (binaryExpression.parent is BinaryExpression) { 1240 BinaryExpression newBinaryExpression =
1188 BinaryExpression newBinaryExpression = 1241 binaryExpression.parent as BinaryExpression;
1189 binaryExpression.parent as BinaryExpression; 1242 if (newBinaryExpression.operator.type != binaryExpression.operator.type) {
1190 if (newBinaryExpression.operator.type != 1243 _coverageMarker();
1191 binaryExpression.operator.type) { 1244 break;
1192 _coverageMarker();
1193 break;
1194 }
1195 binaryExpression = newBinaryExpression;
1196 } 1245 }
1197 // exchange parts of "wide" expression parts 1246 binaryExpression = newBinaryExpression;
1198 SourceRange leftRange = range.startEnd(binaryExpression, leftOperand); 1247 }
1199 SourceRange rightRange = range.startEnd(rightOperand, binaryExpression); 1248 // exchange parts of "wide" expression parts
1200 _addReplaceEdit(leftRange, _getRangeText(rightRange)); 1249 SourceRange leftRange = range.startEnd(binaryExpression, leftOperand);
1201 _addReplaceEdit(rightRange, _getRangeText(leftRange)); 1250 SourceRange rightRange = range.startEnd(rightOperand, binaryExpression);
1202 // maybe replace the operator 1251 // maybe replace the operator
1203 { 1252 Token operator = binaryExpression.operator;
1204 Token operator = binaryExpression.operator; 1253 // prepare a new operator
1205 // prepare a new operator 1254 String newOperator = null;
1206 String newOperator = null; 1255 TokenType operatorType = operator.type;
1207 TokenType operatorType = operator.type; 1256 if (operatorType == TokenType.LT) {
1208 if (operatorType == TokenType.LT) { 1257 newOperator = '>';
1209 newOperator = '>'; 1258 } else if (operatorType == TokenType.LT_EQ) {
1210 } else if (operatorType == TokenType.LT_EQ) { 1259 newOperator = '>=';
1211 newOperator = '>='; 1260 } else if (operatorType == TokenType.GT) {
1212 } else if (operatorType == TokenType.GT) { 1261 newOperator = '<';
1213 newOperator = '<'; 1262 } else if (operatorType == TokenType.GT_EQ) {
1214 } else if (operatorType == TokenType.GT_EQ) { 1263 newOperator = '<=';
1215 newOperator = '<='; 1264 }
1216 } 1265 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1217 // replace the operator 1266 await changeBuilder.addFileEdit(file, fileStamp,
1218 if (newOperator != null) { 1267 (DartFileEditBuilder builder) {
1219 _addReplaceEdit(range.token(operator), newOperator); 1268 builder.addSimpleReplacement(leftRange, _getRangeText(rightRange));
1220 } 1269 builder.addSimpleReplacement(rightRange, _getRangeText(leftRange));
1270 // Optionally replace the operator.
1271 if (newOperator != null) {
1272 builder.addSimpleReplacement(range.token(operator), newOperator);
1221 } 1273 }
1222 } 1274 });
1223 // add proposal 1275 _addAssistFromBuilder(changeBuilder, DartAssistKind.EXCHANGE_OPERANDS);
1224 _addAssist(DartAssistKind.EXCHANGE_OPERANDS, []);
1225 } 1276 }
1226 1277
1227 void _addProposal_importAddShow() { 1278 Future<Null> _addProposal_importAddShow() async {
1228 // prepare ImportDirective 1279 // prepare ImportDirective
1229 ImportDirective importDirective = 1280 ImportDirective importDirective =
1230 node.getAncestor((node) => node is ImportDirective); 1281 node.getAncestor((node) => node is ImportDirective);
1231 if (importDirective == null) { 1282 if (importDirective == null) {
1232 _coverageMarker(); 1283 _coverageMarker();
1233 return; 1284 return;
1234 } 1285 }
1235 // there should be no existing combinators 1286 // there should be no existing combinators
1236 if (importDirective.combinators.isNotEmpty) { 1287 if (importDirective.combinators.isNotEmpty) {
1237 _coverageMarker(); 1288 _coverageMarker();
(...skipping 14 matching lines...) Expand all
1252 if (element != null && namespace[node.name] == element) { 1303 if (element != null && namespace[node.name] == element) {
1253 referencedNames.add(element.displayName); 1304 referencedNames.add(element.displayName);
1254 } 1305 }
1255 }); 1306 });
1256 unit.accept(visitor); 1307 unit.accept(visitor);
1257 // ignore if unused 1308 // ignore if unused
1258 if (referencedNames.isEmpty) { 1309 if (referencedNames.isEmpty) {
1259 _coverageMarker(); 1310 _coverageMarker();
1260 return; 1311 return;
1261 } 1312 }
1262 // prepare change 1313 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1263 String showCombinator = ' show ${referencedNames.join(', ')}'; 1314 await changeBuilder.addFileEdit(file, fileStamp,
1264 _addInsertEdit(importDirective.end - 1, showCombinator); 1315 (DartFileEditBuilder builder) {
1265 // add proposal 1316 String showCombinator = ' show ${referencedNames.join(', ')}';
1266 _addAssist(DartAssistKind.IMPORT_ADD_SHOW, []); 1317 builder.addSimpleInsertion(importDirective.end - 1, showCombinator);
1318 });
1319 _addAssistFromBuilder(changeBuilder, DartAssistKind.IMPORT_ADD_SHOW);
1267 } 1320 }
1268 1321
1269 void _addProposal_introduceLocalTestedType() { 1322 Future<Null> _addProposal_introduceLocalTestedType() async {
1270 AstNode node = this.node; 1323 AstNode node = this.node;
1271 if (node is IfStatement) { 1324 if (node is IfStatement) {
1272 node = (node as IfStatement).condition; 1325 node = (node as IfStatement).condition;
1273 } else if (node is WhileStatement) { 1326 } else if (node is WhileStatement) {
1274 node = (node as WhileStatement).condition; 1327 node = (node as WhileStatement).condition;
1275 } 1328 }
1276 // prepare IsExpression 1329 // prepare IsExpression
1277 if (node is! IsExpression) { 1330 if (node is! IsExpression) {
1278 _coverageMarker(); 1331 _coverageMarker();
1279 return; 1332 return;
(...skipping 20 matching lines...) Expand all
1300 // prepare location 1353 // prepare location
1301 int offset; 1354 int offset;
1302 String statementPrefix; 1355 String statementPrefix;
1303 if (isExpression.notOperator == null) { 1356 if (isExpression.notOperator == null) {
1304 offset = targetBlock.leftBracket.end; 1357 offset = targetBlock.leftBracket.end;
1305 statementPrefix = indent; 1358 statementPrefix = indent;
1306 } else { 1359 } else {
1307 offset = targetBlock.rightBracket.end; 1360 offset = targetBlock.rightBracket.end;
1308 statementPrefix = ''; 1361 statementPrefix = '';
1309 } 1362 }
1310 // prepare source
1311 SourceBuilder builder = new SourceBuilder(file, offset);
1312 builder.append(eol + prefix + statementPrefix);
1313 builder.append(castTypeCode);
1314 // prepare excluded names 1363 // prepare excluded names
1315 Set<String> excluded = new Set<String>(); 1364 Set<String> excluded = new Set<String>();
1316 { 1365 ScopedNameFinder scopedNameFinder = new ScopedNameFinder(offset);
1317 ScopedNameFinder scopedNameFinder = new ScopedNameFinder(offset); 1366 isExpression.accept(scopedNameFinder);
1318 isExpression.accept(scopedNameFinder); 1367 excluded.addAll(scopedNameFinder.locals.keys.toSet());
1319 excluded.addAll(scopedNameFinder.locals.keys.toSet()); 1368 // name(s)
1369 List<String> suggestions =
1370 getVariableNameSuggestionsForExpression(castType, null, excluded);
1371
1372 if (suggestions.isNotEmpty) {
1373 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1374 await changeBuilder.addFileEdit(file, fileStamp,
1375 (DartFileEditBuilder builder) {
1376 builder.addInsertion(offset, (DartEditBuilder builder) {
1377 builder.write(eol + prefix + statementPrefix);
1378 builder.write(castTypeCode);
1379 builder.write(' ');
1380 builder.addSimpleLinkedEdit('NAME', suggestions[0],
1381 kind: LinkedEditSuggestionKind.VARIABLE,
1382 suggestions: suggestions);
1383 builder.write(' = ');
1384 builder.write(_getNodeText(isExpression.expression));
1385 builder.write(';');
1386 builder.selectHere();
1387 });
1388 });
1389 _addAssistFromBuilder(
1390 changeBuilder, DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
1320 } 1391 }
1321 // name(s)
1322 {
1323 List<String> suggestions =
1324 getVariableNameSuggestionsForExpression(castType, null, excluded);
1325 builder.append(' ');
1326 builder.startPosition('NAME');
1327 for (int i = 0; i < suggestions.length; i++) {
1328 String name = suggestions[i];
1329 if (i == 0) {
1330 builder.append(name);
1331 }
1332 builder.addSuggestion(LinkedEditSuggestionKind.VARIABLE, name);
1333 }
1334 builder.endPosition();
1335 }
1336 builder.append(' = ');
1337 builder.append(_getNodeText(isExpression.expression));
1338 builder.append(';');
1339 builder.setExitOffset();
1340 // add proposal
1341 _insertBuilder(builder);
1342 _addAssist(DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, []);
1343 } 1392 }
1344 1393
1345 void _addProposal_invertIf() { 1394 Future<Null> _addProposal_invertIf() async {
1346 if (node is! IfStatement) { 1395 if (node is! IfStatement) {
1347 return; 1396 return;
1348 } 1397 }
1349 IfStatement ifStatement = node as IfStatement; 1398 IfStatement ifStatement = node as IfStatement;
1350 Expression condition = ifStatement.condition; 1399 Expression condition = ifStatement.condition;
1351 // should have both "then" and "else" 1400 // should have both "then" and "else"
1352 Statement thenStatement = ifStatement.thenStatement; 1401 Statement thenStatement = ifStatement.thenStatement;
1353 Statement elseStatement = ifStatement.elseStatement; 1402 Statement elseStatement = ifStatement.elseStatement;
1354 if (thenStatement == null || elseStatement == null) { 1403 if (thenStatement == null || elseStatement == null) {
1355 return; 1404 return;
1356 } 1405 }
1357 // prepare source 1406 // prepare source
1358 String invertedCondition = utils.invertCondition(condition); 1407 String invertedCondition = utils.invertCondition(condition);
1359 String thenSource = _getNodeText(thenStatement); 1408 String thenSource = _getNodeText(thenStatement);
1360 String elseSource = _getNodeText(elseStatement); 1409 String elseSource = _getNodeText(elseStatement);
1361 // do replacements 1410
1362 _addReplaceEdit(range.node(condition), invertedCondition); 1411 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1363 _addReplaceEdit(range.node(thenStatement), elseSource); 1412 await changeBuilder.addFileEdit(file, fileStamp,
1364 _addReplaceEdit(range.node(elseStatement), thenSource); 1413 (DartFileEditBuilder builder) {
1365 // add proposal 1414 builder.addSimpleReplacement(range.node(condition), invertedCondition);
1366 _addAssist(DartAssistKind.INVERT_IF_STATEMENT, []); 1415 builder.addSimpleReplacement(range.node(thenStatement), elseSource);
1416 builder.addSimpleReplacement(range.node(elseStatement), thenSource);
1417 });
1418 _addAssistFromBuilder(changeBuilder, DartAssistKind.INVERT_IF_STATEMENT);
1367 } 1419 }
1368 1420
1369 void _addProposal_joinIfStatementInner() { 1421 Future<Null> _addProposal_joinIfStatementInner() async {
1370 // climb up condition to the (supposedly) "if" statement 1422 // climb up condition to the (supposedly) "if" statement
1371 AstNode node = this.node; 1423 AstNode node = this.node;
1372 while (node is Expression) { 1424 while (node is Expression) {
1373 node = node.parent; 1425 node = node.parent;
1374 } 1426 }
1375 // prepare target "if" statement 1427 // prepare target "if" statement
1376 if (node is! IfStatement) { 1428 if (node is! IfStatement) {
1377 _coverageMarker(); 1429 _coverageMarker();
1378 return; 1430 return;
1379 } 1431 }
(...skipping 25 matching lines...) Expand all
1405 String innerConditionSource = _getNodeText(innerCondition); 1457 String innerConditionSource = _getNodeText(innerCondition);
1406 if (_shouldWrapParenthesisBeforeAnd(targetCondition)) { 1458 if (_shouldWrapParenthesisBeforeAnd(targetCondition)) {
1407 targetConditionSource = '($targetConditionSource)'; 1459 targetConditionSource = '($targetConditionSource)';
1408 } 1460 }
1409 if (_shouldWrapParenthesisBeforeAnd(innerCondition)) { 1461 if (_shouldWrapParenthesisBeforeAnd(innerCondition)) {
1410 innerConditionSource = '($innerConditionSource)'; 1462 innerConditionSource = '($innerConditionSource)';
1411 } 1463 }
1412 condition = '$targetConditionSource && $innerConditionSource'; 1464 condition = '$targetConditionSource && $innerConditionSource';
1413 } 1465 }
1414 // replace target "if" statement 1466 // replace target "if" statement
1415 { 1467 Statement innerThenStatement = innerIfStatement.thenStatement;
1416 Statement innerThenStatement = innerIfStatement.thenStatement; 1468 List<Statement> innerThenStatements = getStatements(innerThenStatement);
1417 List<Statement> innerThenStatements = getStatements(innerThenStatement); 1469 SourceRange lineRanges = utils.getLinesRangeStatements(innerThenStatements);
1418 SourceRange lineRanges = 1470 String oldSource = utils.getRangeText(lineRanges);
1419 utils.getLinesRangeStatements(innerThenStatements); 1471 String newSource = utils.indentSourceLeftRight(oldSource, false);
1420 String oldSource = utils.getRangeText(lineRanges); 1472
1421 String newSource = utils.indentSourceLeftRight(oldSource, false); 1473 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1422 _addReplaceEdit(range.node(targetIfStatement), 1474 await changeBuilder.addFileEdit(file, fileStamp,
1475 (DartFileEditBuilder builder) {
1476 builder.addSimpleReplacement(range.node(targetIfStatement),
1423 'if ($condition) {$eol$newSource$prefix}'); 1477 'if ($condition) {$eol$newSource$prefix}');
1424 } 1478 });
1425 // done 1479 _addAssistFromBuilder(changeBuilder, DartAssistKind.JOIN_IF_WITH_INNER);
1426 _addAssist(DartAssistKind.JOIN_IF_WITH_INNER, []);
1427 } 1480 }
1428 1481
1429 void _addProposal_joinIfStatementOuter() { 1482 Future<Null> _addProposal_joinIfStatementOuter() async {
1430 // climb up condition to the (supposedly) "if" statement 1483 // climb up condition to the (supposedly) "if" statement
1431 AstNode node = this.node; 1484 AstNode node = this.node;
1432 while (node is Expression) { 1485 while (node is Expression) {
1433 node = node.parent; 1486 node = node.parent;
1434 } 1487 }
1435 // prepare target "if" statement 1488 // prepare target "if" statement
1436 if (node is! IfStatement) { 1489 if (node is! IfStatement) {
1437 _coverageMarker(); 1490 _coverageMarker();
1438 return; 1491 return;
1439 } 1492 }
(...skipping 16 matching lines...) Expand all
1456 return; 1509 return;
1457 } 1510 }
1458 IfStatement outerIfStatement = parent as IfStatement; 1511 IfStatement outerIfStatement = parent as IfStatement;
1459 if (outerIfStatement.elseStatement != null) { 1512 if (outerIfStatement.elseStatement != null) {
1460 _coverageMarker(); 1513 _coverageMarker();
1461 return; 1514 return;
1462 } 1515 }
1463 // prepare environment 1516 // prepare environment
1464 String prefix = utils.getNodePrefix(outerIfStatement); 1517 String prefix = utils.getNodePrefix(outerIfStatement);
1465 // merge conditions 1518 // merge conditions
1466 String condition; 1519 Expression targetCondition = targetIfStatement.condition;
1467 { 1520 Expression outerCondition = outerIfStatement.condition;
1468 Expression targetCondition = targetIfStatement.condition; 1521 String targetConditionSource = _getNodeText(targetCondition);
1469 Expression outerCondition = outerIfStatement.condition; 1522 String outerConditionSource = _getNodeText(outerCondition);
1470 String targetConditionSource = _getNodeText(targetCondition); 1523 if (_shouldWrapParenthesisBeforeAnd(targetCondition)) {
1471 String outerConditionSource = _getNodeText(outerCondition); 1524 targetConditionSource = '($targetConditionSource)';
1472 if (_shouldWrapParenthesisBeforeAnd(targetCondition)) {
1473 targetConditionSource = '($targetConditionSource)';
1474 }
1475 if (_shouldWrapParenthesisBeforeAnd(outerCondition)) {
1476 outerConditionSource = '($outerConditionSource)';
1477 }
1478 condition = '$outerConditionSource && $targetConditionSource';
1479 } 1525 }
1526 if (_shouldWrapParenthesisBeforeAnd(outerCondition)) {
1527 outerConditionSource = '($outerConditionSource)';
1528 }
1529 String condition = '$outerConditionSource && $targetConditionSource';
1480 // replace outer "if" statement 1530 // replace outer "if" statement
1481 { 1531 Statement targetThenStatement = targetIfStatement.thenStatement;
1482 Statement targetThenStatement = targetIfStatement.thenStatement; 1532 List<Statement> targetThenStatements = getStatements(targetThenStatement);
1483 List<Statement> targetThenStatements = getStatements(targetThenStatement); 1533 SourceRange lineRanges =
1484 SourceRange lineRanges = 1534 utils.getLinesRangeStatements(targetThenStatements);
1485 utils.getLinesRangeStatements(targetThenStatements); 1535 String oldSource = utils.getRangeText(lineRanges);
1486 String oldSource = utils.getRangeText(lineRanges); 1536 String newSource = utils.indentSourceLeftRight(oldSource, false);
1487 String newSource = utils.indentSourceLeftRight(oldSource, false); 1537
1488 _addReplaceEdit(range.node(outerIfStatement), 1538 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1539 await changeBuilder.addFileEdit(file, fileStamp,
1540 (DartFileEditBuilder builder) {
1541 builder.addSimpleReplacement(range.node(outerIfStatement),
1489 'if ($condition) {$eol$newSource$prefix}'); 1542 'if ($condition) {$eol$newSource$prefix}');
1490 } 1543 });
1491 // done 1544 _addAssistFromBuilder(changeBuilder, DartAssistKind.JOIN_IF_WITH_OUTER);
1492 _addAssist(DartAssistKind.JOIN_IF_WITH_OUTER, []);
1493 } 1545 }
1494 1546
1495 void _addProposal_joinVariableDeclaration_onAssignment() { 1547 Future<Null> _addProposal_joinVariableDeclaration_onAssignment() async {
1496 // check that node is LHS in assignment 1548 // check that node is LHS in assignment
1497 if (node is SimpleIdentifier && 1549 if (node is SimpleIdentifier &&
1498 node.parent is AssignmentExpression && 1550 node.parent is AssignmentExpression &&
1499 (node.parent as AssignmentExpression).leftHandSide == node && 1551 (node.parent as AssignmentExpression).leftHandSide == node &&
1500 node.parent.parent is ExpressionStatement) {} else { 1552 node.parent.parent is ExpressionStatement) {} else {
1501 _coverageMarker(); 1553 _coverageMarker();
1502 return; 1554 return;
1503 } 1555 }
1504 AssignmentExpression assignExpression = node.parent as AssignmentExpression; 1556 AssignmentExpression assignExpression = node.parent as AssignmentExpression;
1505 // check that binary expression is assignment 1557 // check that binary expression is assignment
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1546 return; 1598 return;
1547 } 1599 }
1548 Block block = assignStatement.parent as Block; 1600 Block block = assignStatement.parent as Block;
1549 // check that "declaration" and "assignment" statements are adjacent 1601 // check that "declaration" and "assignment" statements are adjacent
1550 List<Statement> statements = block.statements; 1602 List<Statement> statements = block.statements;
1551 if (statements.indexOf(assignStatement) == 1603 if (statements.indexOf(assignStatement) ==
1552 statements.indexOf(declStatement) + 1) {} else { 1604 statements.indexOf(declStatement) + 1) {} else {
1553 _coverageMarker(); 1605 _coverageMarker();
1554 return; 1606 return;
1555 } 1607 }
1556 // add edits 1608
1557 _addReplaceEdit(range.endStart(declNode, assignExpression.operator), ' '); 1609 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1558 // add proposal 1610 await changeBuilder.addFileEdit(file, fileStamp,
1559 _addAssist(DartAssistKind.JOIN_VARIABLE_DECLARATION, []); 1611 (DartFileEditBuilder builder) {
1612 builder.addSimpleReplacement(
1613 range.endStart(declNode, assignExpression.operator), ' ');
1614 });
1615 _addAssistFromBuilder(
1616 changeBuilder, DartAssistKind.JOIN_VARIABLE_DECLARATION);
1560 } 1617 }
1561 1618
1562 void _addProposal_joinVariableDeclaration_onDeclaration() { 1619 Future<Null> _addProposal_joinVariableDeclaration_onDeclaration() async {
1563 // prepare enclosing VariableDeclarationList 1620 // prepare enclosing VariableDeclarationList
1564 VariableDeclarationList declList = 1621 VariableDeclarationList declList =
1565 node.getAncestor((node) => node is VariableDeclarationList); 1622 node.getAncestor((node) => node is VariableDeclarationList);
1566 if (declList != null && declList.variables.length == 1) {} else { 1623 if (declList != null && declList.variables.length == 1) {} else {
1567 _coverageMarker(); 1624 _coverageMarker();
1568 return; 1625 return;
1569 } 1626 }
1570 VariableDeclaration decl = declList.variables[0]; 1627 VariableDeclaration decl = declList.variables[0];
1571 // already initialized 1628 // already initialized
1572 if (decl.initializer != null) { 1629 if (decl.initializer != null) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1605 _coverageMarker(); 1662 _coverageMarker();
1606 return; 1663 return;
1607 } 1664 }
1608 assignExpression = expressionStatement.expression as AssignmentExpression; 1665 assignExpression = expressionStatement.expression as AssignmentExpression;
1609 } 1666 }
1610 // check that pure assignment 1667 // check that pure assignment
1611 if (assignExpression.operator.type != TokenType.EQ) { 1668 if (assignExpression.operator.type != TokenType.EQ) {
1612 _coverageMarker(); 1669 _coverageMarker();
1613 return; 1670 return;
1614 } 1671 }
1615 // add edits 1672
1616 _addReplaceEdit(range.endStart(decl.name, assignExpression.operator), ' '); 1673 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1617 // add proposal 1674 await changeBuilder.addFileEdit(file, fileStamp,
1618 _addAssist(DartAssistKind.JOIN_VARIABLE_DECLARATION, []); 1675 (DartFileEditBuilder builder) {
1676 builder.addSimpleReplacement(
1677 range.endStart(decl.name, assignExpression.operator), ' ');
1678 });
1679 _addAssistFromBuilder(
1680 changeBuilder, DartAssistKind.JOIN_VARIABLE_DECLARATION);
1619 } 1681 }
1620 1682
1621 void _addProposal_moveFlutterWidgetDown() { 1683 Future<Null> _addProposal_moveFlutterWidgetDown() async {
1622 InstanceCreationExpression exprGoingDown = identifyNewExpression(node); 1684 InstanceCreationExpression exprGoingDown = identifyNewExpression(node);
1623 if (exprGoingDown == null || 1685 if (exprGoingDown == null ||
1624 !isFlutterInstanceCreationExpression(exprGoingDown)) { 1686 !isFlutterInstanceCreationExpression(exprGoingDown)) {
1625 _coverageMarker(); 1687 _coverageMarker();
1626 return; 1688 return;
1627 } 1689 }
1628 InstanceCreationExpression exprGoingUp = findChildWidget(exprGoingDown); 1690 InstanceCreationExpression exprGoingUp = findChildWidget(exprGoingDown);
1629 if (exprGoingUp == null) { 1691 if (exprGoingUp == null) {
1630 _coverageMarker(); 1692 _coverageMarker();
1631 return; 1693 return;
1632 } 1694 }
1633 NamedExpression stableChild = findChildArgument(exprGoingUp); 1695 NamedExpression stableChild = findChildArgument(exprGoingUp);
1634 if (stableChild == null || stableChild.expression == null) { 1696 if (stableChild == null || stableChild.expression == null) {
1635 _coverageMarker(); 1697 _coverageMarker();
1636 return; 1698 return;
1637 } 1699 }
1638 String exprGoingDownSrc = utils.getNodeText(exprGoingDown); 1700 String exprGoingDownSrc = utils.getNodeText(exprGoingDown);
1639 int dnNewlineIdx = exprGoingDownSrc.lastIndexOf(eol); 1701 int dnNewlineIdx = exprGoingDownSrc.lastIndexOf(eol);
1640 if (dnNewlineIdx < 0 || dnNewlineIdx == exprGoingDownSrc.length - 1) { 1702 if (dnNewlineIdx < 0 || dnNewlineIdx == exprGoingDownSrc.length - 1) {
1641 _coverageMarker(); 1703 _coverageMarker();
1642 return; // Outer new-expr needs to be in multi-line format already. 1704 return; // Outer new-expr needs to be in multi-line format already.
1643 } 1705 }
1644 String exprGoingUpSrc = utils.getNodeText(exprGoingUp); 1706 String exprGoingUpSrc = utils.getNodeText(exprGoingUp);
1645 int upNewlineIdx = exprGoingUpSrc.lastIndexOf(eol); 1707 int upNewlineIdx = exprGoingUpSrc.lastIndexOf(eol);
1646 if (upNewlineIdx < 0 || upNewlineIdx == exprGoingUpSrc.length - 1) { 1708 if (upNewlineIdx < 0 || upNewlineIdx == exprGoingUpSrc.length - 1) {
1647 _coverageMarker(); 1709 _coverageMarker();
1648 return; // Inner new-expr needs to be in multi-line format already. 1710 return; // Inner new-expr needs to be in multi-line format already.
1649 } 1711 }
1650 _swapFlutterWidgets(exprGoingDown, exprGoingUp, stableChild, 1712 await _swapFlutterWidgets(exprGoingDown, exprGoingUp, stableChild,
1651 DartAssistKind.MOVE_FLUTTER_WIDGET_DOWN); 1713 DartAssistKind.MOVE_FLUTTER_WIDGET_DOWN);
1652 } 1714 }
1653 1715
1654 void _addProposal_moveFlutterWidgetUp() { 1716 Future<Null> _addProposal_moveFlutterWidgetUp() async {
1655 InstanceCreationExpression exprGoingUp = identifyNewExpression(node); 1717 InstanceCreationExpression exprGoingUp = identifyNewExpression(node);
1656 if (exprGoingUp == null || 1718 if (exprGoingUp == null ||
1657 !isFlutterInstanceCreationExpression(exprGoingUp)) { 1719 !isFlutterInstanceCreationExpression(exprGoingUp)) {
1658 _coverageMarker(); 1720 _coverageMarker();
1659 return; 1721 return;
1660 } 1722 }
1661 AstNode expr = exprGoingUp.parent?.parent?.parent; 1723 AstNode expr = exprGoingUp.parent?.parent?.parent;
1662 if (expr == null || expr is! InstanceCreationExpression) { 1724 if (expr == null || expr is! InstanceCreationExpression) {
1663 _coverageMarker(); 1725 _coverageMarker();
1664 return; 1726 return;
1665 } 1727 }
1666 InstanceCreationExpression exprGoingDown = expr; 1728 InstanceCreationExpression exprGoingDown = expr;
1667 NamedExpression stableChild = findChildArgument(exprGoingUp); 1729 NamedExpression stableChild = findChildArgument(exprGoingUp);
1668 if (stableChild == null || stableChild.expression == null) { 1730 if (stableChild == null || stableChild.expression == null) {
1669 _coverageMarker(); 1731 _coverageMarker();
1670 return; 1732 return;
1671 } 1733 }
1672 String exprGoingUpSrc = utils.getNodeText(exprGoingUp); 1734 String exprGoingUpSrc = utils.getNodeText(exprGoingUp);
1673 int upNewlineIdx = exprGoingUpSrc.lastIndexOf(eol); 1735 int upNewlineIdx = exprGoingUpSrc.lastIndexOf(eol);
1674 if (upNewlineIdx < 0 || upNewlineIdx == exprGoingUpSrc.length - 1) { 1736 if (upNewlineIdx < 0 || upNewlineIdx == exprGoingUpSrc.length - 1) {
1675 _coverageMarker(); 1737 _coverageMarker();
1676 return; // Inner new-expr needs to be in multi-line format already. 1738 return; // Inner new-expr needs to be in multi-line format already.
1677 } 1739 }
1678 String exprGoingDownSrc = utils.getNodeText(exprGoingDown); 1740 String exprGoingDownSrc = utils.getNodeText(exprGoingDown);
1679 int dnNewlineIdx = exprGoingDownSrc.lastIndexOf(eol); 1741 int dnNewlineIdx = exprGoingDownSrc.lastIndexOf(eol);
1680 if (dnNewlineIdx < 0 || dnNewlineIdx == exprGoingDownSrc.length - 1) { 1742 if (dnNewlineIdx < 0 || dnNewlineIdx == exprGoingDownSrc.length - 1) {
1681 _coverageMarker(); 1743 _coverageMarker();
1682 return; // Outer new-expr needs to be in multi-line format already. 1744 return; // Outer new-expr needs to be in multi-line format already.
1683 } 1745 }
1684 _swapFlutterWidgets(exprGoingDown, exprGoingUp, stableChild, 1746 await _swapFlutterWidgets(exprGoingDown, exprGoingUp, stableChild,
1685 DartAssistKind.MOVE_FLUTTER_WIDGET_UP); 1747 DartAssistKind.MOVE_FLUTTER_WIDGET_UP);
1686 } 1748 }
1687 1749
1688 void _addProposal_removeTypeAnnotation() { 1750 Future<Null> _addProposal_removeTypeAnnotation() async {
1689 VariableDeclarationList declarationList = 1751 VariableDeclarationList declarationList =
1690 node.getAncestor((n) => n is VariableDeclarationList); 1752 node.getAncestor((n) => n is VariableDeclarationList);
1691 if (declarationList == null) { 1753 if (declarationList == null) {
1692 _coverageMarker(); 1754 _coverageMarker();
1693 return; 1755 return;
1694 } 1756 }
1695 // we need a type 1757 // we need a type
1696 TypeAnnotation typeNode = declarationList.type; 1758 TypeAnnotation typeNode = declarationList.type;
1697 if (typeNode == null) { 1759 if (typeNode == null) {
1698 _coverageMarker(); 1760 _coverageMarker();
1699 return; 1761 return;
1700 } 1762 }
1701 // ignore if an incomplete variable declaration 1763 // ignore if an incomplete variable declaration
1702 if (declarationList.variables.length == 1 && 1764 if (declarationList.variables.length == 1 &&
1703 declarationList.variables[0].name.isSynthetic) { 1765 declarationList.variables[0].name.isSynthetic) {
1704 _coverageMarker(); 1766 _coverageMarker();
1705 return; 1767 return;
1706 } 1768 }
1707 // must be not after the name of the variable 1769 // must be not after the name of the variable
1708 VariableDeclaration firstVariable = declarationList.variables[0]; 1770 VariableDeclaration firstVariable = declarationList.variables[0];
1709 if (selectionOffset > firstVariable.name.end) { 1771 if (selectionOffset > firstVariable.name.end) {
1710 _coverageMarker(); 1772 _coverageMarker();
1711 return; 1773 return;
1712 } 1774 }
1713 // add edit 1775 // add edit
1714 Token keyword = declarationList.keyword; 1776 Token keyword = declarationList.keyword;
1715 SourceRange typeRange = range.startStart(typeNode, firstVariable); 1777 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1716 if (keyword != null && keyword.lexeme != 'var') { 1778 await changeBuilder.addFileEdit(file, fileStamp,
1717 _addReplaceEdit(typeRange, ''); 1779 (DartFileEditBuilder builder) {
1718 } else { 1780 SourceRange typeRange = range.startStart(typeNode, firstVariable);
1719 _addReplaceEdit(typeRange, 'var '); 1781 if (keyword != null && keyword.lexeme != 'var') {
1720 } 1782 builder.addSimpleReplacement(typeRange, '');
1721 // add proposal 1783 } else {
1722 _addAssist(DartAssistKind.REMOVE_TYPE_ANNOTATION, []); 1784 builder.addSimpleReplacement(typeRange, 'var ');
1785 }
1786 });
1787 _addAssistFromBuilder(changeBuilder, DartAssistKind.REMOVE_TYPE_ANNOTATION);
1723 } 1788 }
1724 1789
1725 void _addProposal_reparentFlutterList() { 1790 Future<Null> _addProposal_reparentFlutterList() async {
1726 if (node is! ListLiteral) { 1791 if (node is! ListLiteral) {
1727 return; 1792 return;
1728 } 1793 }
1729 if ((node as ListLiteral).elements.any((Expression exp) => 1794 if ((node as ListLiteral).elements.any((Expression exp) =>
1730 !(exp is InstanceCreationExpression && 1795 !(exp is InstanceCreationExpression &&
1731 isFlutterInstanceCreationExpression(exp)))) { 1796 isFlutterInstanceCreationExpression(exp)))) {
1732 _coverageMarker(); 1797 _coverageMarker();
1733 return; 1798 return;
1734 } 1799 }
1735 String literalSrc = utils.getNodeText(node); 1800 String literalSrc = utils.getNodeText(node);
1736 SourceBuilder sb = new SourceBuilder(file, node.offset);
1737 int newlineIdx = literalSrc.lastIndexOf(eol); 1801 int newlineIdx = literalSrc.lastIndexOf(eol);
1738 if (newlineIdx < 0 || newlineIdx == literalSrc.length - 1) { 1802 if (newlineIdx < 0 || newlineIdx == literalSrc.length - 1) {
1739 _coverageMarker(); 1803 _coverageMarker();
1740 return; // Lists need to be in multi-line format already. 1804 return; // Lists need to be in multi-line format already.
1741 } 1805 }
1742 String indentOld = utils.getLinePrefix(node.offset + 1 + newlineIdx); 1806 String indentOld = utils.getLinePrefix(node.offset + 1 + newlineIdx);
1743 String indentArg = '$indentOld${utils.getIndent(1)}'; 1807 String indentArg = '$indentOld${utils.getIndent(1)}';
1744 String indentList = '$indentOld${utils.getIndent(2)}'; 1808 String indentList = '$indentOld${utils.getIndent(2)}';
1745 sb.append('['); 1809
1746 sb.append(eol); 1810 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1747 sb.append(indentArg); 1811 await changeBuilder.addFileEdit(file, fileStamp,
1748 sb.append('new '); 1812 (DartFileEditBuilder builder) {
1749 sb.startPosition('WIDGET'); 1813 builder.addReplacement(range.node(node), (DartEditBuilder builder) {
1750 sb.append('widget'); 1814 builder.write('[');
1751 sb.endPosition(); 1815 builder.write(eol);
1752 sb.append('('); 1816 builder.write(indentArg);
1753 sb.append(eol); 1817 builder.write('new ');
1754 sb.append(indentList); 1818 builder.addSimpleLinkedEdit('WIDGET', 'widget');
1755 // Linked editing not needed since arg is always a list. 1819 builder.write('(');
1756 sb.append('children: '); 1820 builder.write(eol);
1757 sb.append(literalSrc.replaceAll( 1821 builder.write(indentList);
1758 new RegExp("^$indentOld", multiLine: true), "$indentList")); 1822 // Linked editing not needed since arg is always a list.
1759 sb.append(','); 1823 builder.write('children: ');
1760 sb.append(eol); 1824 builder.write(literalSrc.replaceAll(
1761 sb.append(indentArg); 1825 new RegExp("^$indentOld", multiLine: true), "$indentList"));
1762 sb.append('),'); 1826 builder.write(',');
1763 sb.append(eol); 1827 builder.write(eol);
1764 sb.append(indentOld); 1828 builder.write(indentArg);
1765 sb.append(']'); 1829 builder.write('),');
1766 exitPosition = _newPosition(sb.offset + sb.length); 1830 builder.write(eol);
1767 _insertBuilder(sb, literalSrc.length); 1831 builder.write(indentOld);
1768 _addAssist(DartAssistKind.REPARENT_FLUTTER_LIST, []); 1832 builder.write(']');
1833 builder.selectHere();
1834 });
1835 });
1836 _addAssistFromBuilder(changeBuilder, DartAssistKind.REPARENT_FLUTTER_LIST);
1769 } 1837 }
1770 1838
1771 void _addProposal_reparentFlutterWidget() { 1839 Future<Null> _addProposal_reparentFlutterWidget() async {
1772 InstanceCreationExpression newExpr = identifyNewExpression(node); 1840 InstanceCreationExpression newExpr = identifyNewExpression(node);
1773 if (newExpr == null || !isFlutterInstanceCreationExpression(newExpr)) { 1841 if (newExpr == null || !isFlutterInstanceCreationExpression(newExpr)) {
1774 _coverageMarker(); 1842 _coverageMarker();
1775 return; 1843 return;
1776 } 1844 }
1777 String newExprSrc = utils.getNodeText(newExpr); 1845 String newExprSrc = utils.getNodeText(newExpr);
1778 SourceBuilder sb = new SourceBuilder(file, newExpr.offset); 1846
1779 sb.append('new '); 1847 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1780 sb.startPosition('WIDGET'); 1848 await changeBuilder.addFileEdit(file, fileStamp,
1781 sb.append('widget'); 1849 (DartFileEditBuilder builder) {
1782 sb.endPosition(); 1850 builder.addReplacement(range.node(newExpr), (DartEditBuilder builder) {
1783 sb.append('('); 1851 builder.write('new ');
1784 if (newExprSrc.contains(eol)) { 1852 builder.addSimpleLinkedEdit('WIDGET', 'widget');
1785 int newlineIdx = newExprSrc.lastIndexOf(eol); 1853 builder.write('(');
1786 int eolLen = eol.length; 1854 if (newExprSrc.contains(eol)) {
1787 if (newlineIdx == newExprSrc.length - eolLen) { 1855 int newlineIdx = newExprSrc.lastIndexOf(eol);
1788 newlineIdx -= eolLen; 1856 int eolLen = eol.length;
1789 } 1857 if (newlineIdx == newExprSrc.length - eolLen) {
1790 String indentOld = 1858 newlineIdx -= eolLen;
1791 utils.getLinePrefix(newExpr.offset + eolLen + newlineIdx); 1859 }
1792 String indentNew = '$indentOld${utils.getIndent(1)}'; 1860 String indentOld =
1793 sb.append(eol); 1861 utils.getLinePrefix(newExpr.offset + eolLen + newlineIdx);
1794 sb.append(indentNew); 1862 String indentNew = '$indentOld${utils.getIndent(1)}';
1795 newExprSrc = newExprSrc.replaceAll( 1863 builder.write(eol);
1796 new RegExp("^$indentOld", multiLine: true), "$indentNew"); 1864 builder.write(indentNew);
1797 newExprSrc += ",$eol$indentOld"; 1865 newExprSrc = newExprSrc.replaceAll(
1798 } 1866 new RegExp("^$indentOld", multiLine: true), indentNew);
1799 sb.startPosition('CHILD'); 1867 newExprSrc += ",$eol$indentOld";
1800 sb.append('child'); 1868 }
1801 sb.endPosition(); 1869 builder.addSimpleLinkedEdit('CHILD', 'child');
1802 sb.append(': '); 1870 builder.write(': ');
1803 sb.append(newExprSrc); 1871 builder.write(newExprSrc);
1804 sb.append(')'); 1872 builder.write(')');
1805 exitPosition = _newPosition(sb.offset + sb.length); 1873 builder.selectHere();
1806 _insertBuilder(sb, newExpr.length); 1874 });
1807 _addAssist(DartAssistKind.REPARENT_FLUTTER_WIDGET, []); 1875 });
1876 _addAssistFromBuilder(
1877 changeBuilder, DartAssistKind.REPARENT_FLUTTER_WIDGET);
1808 } 1878 }
1809 1879
1810 void _addProposal_replaceConditionalWithIfElse() { 1880 Future<Null> _addProposal_replaceConditionalWithIfElse() async {
1811 ConditionalExpression conditional = null; 1881 ConditionalExpression conditional = null;
1812 // may be on Statement with Conditional 1882 // may be on Statement with Conditional
1813 Statement statement = node.getAncestor((node) => node is Statement); 1883 Statement statement = node.getAncestor((node) => node is Statement);
1814 if (statement == null) { 1884 if (statement == null) {
1815 _coverageMarker(); 1885 _coverageMarker();
1816 return; 1886 return;
1817 } 1887 }
1818 // variable declaration 1888 // variable declaration
1819 bool inVariable = false; 1889 bool inVariable = false;
1820 if (statement is VariableDeclarationStatement) { 1890 if (statement is VariableDeclarationStatement) {
(...skipping 26 matching lines...) Expand all
1847 if (statement is ReturnStatement) { 1917 if (statement is ReturnStatement) {
1848 ReturnStatement returnStatement = statement; 1918 ReturnStatement returnStatement = statement;
1849 if (returnStatement.expression is ConditionalExpression) { 1919 if (returnStatement.expression is ConditionalExpression) {
1850 conditional = returnStatement.expression as ConditionalExpression; 1920 conditional = returnStatement.expression as ConditionalExpression;
1851 inReturn = true; 1921 inReturn = true;
1852 } 1922 }
1853 } 1923 }
1854 // prepare environment 1924 // prepare environment
1855 String indent = utils.getIndent(1); 1925 String indent = utils.getIndent(1);
1856 String prefix = utils.getNodePrefix(statement); 1926 String prefix = utils.getNodePrefix(statement);
1857 // Type v = Conditional; 1927
1858 if (inVariable) { 1928 if (inVariable || inAssignment || inReturn) {
1859 VariableDeclaration variable = conditional.parent as VariableDeclaration; 1929 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
1860 _addRemoveEdit(range.endEnd(variable.name, conditional)); 1930 await changeBuilder.addFileEdit(file, fileStamp,
1861 String conditionSrc = _getNodeText(conditional.condition); 1931 (DartFileEditBuilder builder) {
1862 String thenSrc = _getNodeText(conditional.thenExpression); 1932 // Type v = Conditional;
1863 String elseSrc = _getNodeText(conditional.elseExpression); 1933 if (inVariable) {
1864 String name = variable.name.name; 1934 VariableDeclaration variable =
1865 String src = eol; 1935 conditional.parent as VariableDeclaration;
1866 src += prefix + 'if ($conditionSrc) {' + eol; 1936 builder.addDeletion(range.endEnd(variable.name, conditional));
1867 src += prefix + indent + '$name = $thenSrc;' + eol; 1937 String conditionSrc = _getNodeText(conditional.condition);
1868 src += prefix + '} else {' + eol; 1938 String thenSrc = _getNodeText(conditional.thenExpression);
1869 src += prefix + indent + '$name = $elseSrc;' + eol; 1939 String elseSrc = _getNodeText(conditional.elseExpression);
1870 src += prefix + '}'; 1940 String name = variable.name.name;
1871 _addReplaceEdit(range.endLength(statement, 0), src); 1941 String src = eol;
1942 src += prefix + 'if ($conditionSrc) {' + eol;
1943 src += prefix + indent + '$name = $thenSrc;' + eol;
1944 src += prefix + '} else {' + eol;
1945 src += prefix + indent + '$name = $elseSrc;' + eol;
1946 src += prefix + '}';
1947 builder.addSimpleReplacement(range.endLength(statement, 0), src);
1948 }
1949 // v = Conditional;
1950 if (inAssignment) {
1951 AssignmentExpression assignment =
1952 conditional.parent as AssignmentExpression;
1953 Expression leftSide = assignment.leftHandSide;
1954 String conditionSrc = _getNodeText(conditional.condition);
1955 String thenSrc = _getNodeText(conditional.thenExpression);
1956 String elseSrc = _getNodeText(conditional.elseExpression);
1957 String name = _getNodeText(leftSide);
1958 String src = '';
1959 src += 'if ($conditionSrc) {' + eol;
1960 src += prefix + indent + '$name = $thenSrc;' + eol;
1961 src += prefix + '} else {' + eol;
1962 src += prefix + indent + '$name = $elseSrc;' + eol;
1963 src += prefix + '}';
1964 builder.addSimpleReplacement(range.node(statement), src);
1965 }
1966 // return Conditional;
1967 if (inReturn) {
1968 String conditionSrc = _getNodeText(conditional.condition);
1969 String thenSrc = _getNodeText(conditional.thenExpression);
1970 String elseSrc = _getNodeText(conditional.elseExpression);
1971 String src = '';
1972 src += 'if ($conditionSrc) {' + eol;
1973 src += prefix + indent + 'return $thenSrc;' + eol;
1974 src += prefix + '} else {' + eol;
1975 src += prefix + indent + 'return $elseSrc;' + eol;
1976 src += prefix + '}';
1977 builder.addSimpleReplacement(range.node(statement), src);
1978 }
1979 });
1980 _addAssistFromBuilder(
1981 changeBuilder, DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
1872 } 1982 }
1873 // v = Conditional;
1874 if (inAssignment) {
1875 AssignmentExpression assignment =
1876 conditional.parent as AssignmentExpression;
1877 Expression leftSide = assignment.leftHandSide;
1878 String conditionSrc = _getNodeText(conditional.condition);
1879 String thenSrc = _getNodeText(conditional.thenExpression);
1880 String elseSrc = _getNodeText(conditional.elseExpression);
1881 String name = _getNodeText(leftSide);
1882 String src = '';
1883 src += 'if ($conditionSrc) {' + eol;
1884 src += prefix + indent + '$name = $thenSrc;' + eol;
1885 src += prefix + '} else {' + eol;
1886 src += prefix + indent + '$name = $elseSrc;' + eol;
1887 src += prefix + '}';
1888 _addReplaceEdit(range.node(statement), src);
1889 }
1890 // return Conditional;
1891 if (inReturn) {
1892 String conditionSrc = _getNodeText(conditional.condition);
1893 String thenSrc = _getNodeText(conditional.thenExpression);
1894 String elseSrc = _getNodeText(conditional.elseExpression);
1895 String src = '';
1896 src += 'if ($conditionSrc) {' + eol;
1897 src += prefix + indent + 'return $thenSrc;' + eol;
1898 src += prefix + '} else {' + eol;
1899 src += prefix + indent + 'return $elseSrc;' + eol;
1900 src += prefix + '}';
1901 _addReplaceEdit(range.node(statement), src);
1902 }
1903 // add proposal
1904 _addAssist(DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE, []);
1905 } 1983 }
1906 1984
1907 void _addProposal_replaceIfElseWithConditional() { 1985 Future<Null> _addProposal_replaceIfElseWithConditional() async {
1908 // should be "if" 1986 // should be "if"
1909 if (node is! IfStatement) { 1987 if (node is! IfStatement) {
1910 _coverageMarker(); 1988 _coverageMarker();
1911 return; 1989 return;
1912 } 1990 }
1913 IfStatement ifStatement = node as IfStatement; 1991 IfStatement ifStatement = node as IfStatement;
1914 // single then/else statements 1992 // single then/else statements
1915 Statement thenStatement = getSingleStatement(ifStatement.thenStatement); 1993 Statement thenStatement = getSingleStatement(ifStatement.thenStatement);
1916 Statement elseStatement = getSingleStatement(ifStatement.elseStatement); 1994 Statement elseStatement = getSingleStatement(ifStatement.elseStatement);
1917 if (thenStatement == null || elseStatement == null) { 1995 if (thenStatement == null || elseStatement == null) {
1918 _coverageMarker(); 1996 _coverageMarker();
1919 return; 1997 return;
1920 } 1998 }
1921 // returns 1999 Expression thenExpression = null;
2000 Expression elseExpression = null;
2001 bool hasReturnStatements = false;
1922 if (thenStatement is ReturnStatement && elseStatement is ReturnStatement) { 2002 if (thenStatement is ReturnStatement && elseStatement is ReturnStatement) {
1923 String conditionSrc = _getNodeText(ifStatement.condition); 2003 hasReturnStatements = true;
1924 String theSrc = _getNodeText(thenStatement.expression); 2004 thenExpression = thenStatement.expression;
1925 String elseSrc = _getNodeText(elseStatement.expression); 2005 elseExpression = elseStatement.expression;
1926 _addReplaceEdit(range.node(ifStatement),
1927 'return $conditionSrc ? $theSrc : $elseSrc;');
1928 } 2006 }
1929 // assignments -> v = Conditional; 2007 bool hasExpressionStatements = false;
1930 if (thenStatement is ExpressionStatement && 2008 if (thenStatement is ExpressionStatement &&
1931 elseStatement is ExpressionStatement) { 2009 elseStatement is ExpressionStatement) {
1932 Expression thenExpression = thenStatement.expression; 2010 if (thenStatement.expression is AssignmentExpression &&
1933 Expression elseExpression = elseStatement.expression; 2011 elseStatement.expression is AssignmentExpression) {
1934 if (thenExpression is AssignmentExpression && 2012 hasExpressionStatements = true;
1935 elseExpression is AssignmentExpression) { 2013 thenExpression = thenStatement.expression;
1936 AssignmentExpression thenAssignment = thenExpression; 2014 elseExpression = elseStatement.expression;
1937 AssignmentExpression elseAssignment = elseExpression;
1938 String thenTarget = _getNodeText(thenAssignment.leftHandSide);
1939 String elseTarget = _getNodeText(elseAssignment.leftHandSide);
1940 if (thenAssignment.operator.type == TokenType.EQ &&
1941 elseAssignment.operator.type == TokenType.EQ &&
1942 thenTarget == elseTarget) {
1943 String conditionSrc = _getNodeText(ifStatement.condition);
1944 String theSrc = _getNodeText(thenAssignment.rightHandSide);
1945 String elseSrc = _getNodeText(elseAssignment.rightHandSide);
1946 _addReplaceEdit(range.node(ifStatement),
1947 '$thenTarget = $conditionSrc ? $theSrc : $elseSrc;');
1948 }
1949 } 2015 }
1950 } 2016 }
1951 // add proposal 2017
1952 _addAssist(DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL, []); 2018 if (hasReturnStatements || hasExpressionStatements) {
2019 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2020 await changeBuilder.addFileEdit(file, fileStamp,
2021 (DartFileEditBuilder builder) {
2022 // returns
2023 if (hasReturnStatements) {
2024 String conditionSrc = _getNodeText(ifStatement.condition);
2025 String theSrc = _getNodeText(thenExpression);
2026 String elseSrc = _getNodeText(elseExpression);
2027 builder.addSimpleReplacement(range.node(ifStatement),
2028 'return $conditionSrc ? $theSrc : $elseSrc;');
2029 }
2030 // assignments -> v = Conditional;
2031 if (hasExpressionStatements) {
2032 AssignmentExpression thenAssignment = thenExpression;
2033 AssignmentExpression elseAssignment = elseExpression;
2034 String thenTarget = _getNodeText(thenAssignment.leftHandSide);
2035 String elseTarget = _getNodeText(elseAssignment.leftHandSide);
2036 if (thenAssignment.operator.type == TokenType.EQ &&
2037 elseAssignment.operator.type == TokenType.EQ &&
2038 thenTarget == elseTarget) {
2039 String conditionSrc = _getNodeText(ifStatement.condition);
2040 String theSrc = _getNodeText(thenAssignment.rightHandSide);
2041 String elseSrc = _getNodeText(elseAssignment.rightHandSide);
2042 builder.addSimpleReplacement(range.node(ifStatement),
2043 '$thenTarget = $conditionSrc ? $theSrc : $elseSrc;');
2044 }
2045 }
2046 });
2047 _addAssistFromBuilder(
2048 changeBuilder, DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
2049 }
1953 } 2050 }
1954 2051
1955 void _addProposal_splitAndCondition() { 2052 Future<Null> _addProposal_splitAndCondition() async {
1956 // check that user invokes quick assist on binary expression 2053 // check that user invokes quick assist on binary expression
1957 if (node is! BinaryExpression) { 2054 if (node is! BinaryExpression) {
1958 _coverageMarker(); 2055 _coverageMarker();
1959 return; 2056 return;
1960 } 2057 }
1961 BinaryExpression binaryExpression = node as BinaryExpression; 2058 BinaryExpression binaryExpression = node as BinaryExpression;
1962 // prepare operator position 2059 // prepare operator position
1963 if (!_isOperatorSelected( 2060 if (!_isOperatorSelected(
1964 binaryExpression, selectionOffset, selectionLength)) { 2061 binaryExpression, selectionOffset, selectionLength)) {
1965 _coverageMarker(); 2062 _coverageMarker();
(...skipping 30 matching lines...) Expand all
1996 // prepare environment 2093 // prepare environment
1997 String prefix = utils.getNodePrefix(ifStatement); 2094 String prefix = utils.getNodePrefix(ifStatement);
1998 String indent = utils.getIndent(1); 2095 String indent = utils.getIndent(1);
1999 // prepare "rightCondition" 2096 // prepare "rightCondition"
2000 String rightConditionSource; 2097 String rightConditionSource;
2001 { 2098 {
2002 SourceRange rightConditionRange = 2099 SourceRange rightConditionRange =
2003 range.startEnd(binaryExpression.rightOperand, condition); 2100 range.startEnd(binaryExpression.rightOperand, condition);
2004 rightConditionSource = _getRangeText(rightConditionRange); 2101 rightConditionSource = _getRangeText(rightConditionRange);
2005 } 2102 }
2006 // remove "&& rightCondition" 2103
2007 _addRemoveEdit(range.endEnd(binaryExpression.leftOperand, condition)); 2104 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2008 // update "then" statement 2105 await changeBuilder.addFileEdit(file, fileStamp,
2009 Statement thenStatement = ifStatement.thenStatement; 2106 (DartFileEditBuilder builder) {
2010 if (thenStatement is Block) { 2107 // remove "&& rightCondition"
2011 Block thenBlock = thenStatement; 2108 builder
2012 SourceRange thenBlockRange = range.node(thenBlock); 2109 .addDeletion(range.endEnd(binaryExpression.leftOperand, condition));
2013 // insert inner "if" with right part of "condition" 2110 // update "then" statement
2111 Statement thenStatement = ifStatement.thenStatement;
2112 if (thenStatement is Block) {
2113 Block thenBlock = thenStatement;
2114 SourceRange thenBlockRange = range.node(thenBlock);
2115 // insert inner "if" with right part of "condition"
2116 int thenBlockInsideOffset = thenBlockRange.offset + 1;
2117 builder.addSimpleInsertion(thenBlockInsideOffset,
2118 '$eol$prefix${indent}if ($rightConditionSource) {');
2119 // insert closing "}" for inner "if"
2120 int thenBlockEnd = thenBlockRange.end;
2121 // insert before outer "then" block "}"
2122 builder.addSimpleInsertion(thenBlockEnd - 1, '$indent}$eol$prefix');
2123 } else {
2124 // insert inner "if" with right part of "condition"
2125 String source = '$eol$prefix${indent}if ($rightConditionSource)';
2126 builder.addSimpleInsertion(
2127 ifStatement.rightParenthesis.offset + 1, source);
2128 }
2129 // indent "then" statements to correspond inner "if"
2014 { 2130 {
2015 String source = '$eol$prefix${indent}if ($rightConditionSource) {'; 2131 List<Statement> thenStatements = getStatements(thenStatement);
2016 int thenBlockInsideOffset = thenBlockRange.offset + 1; 2132 SourceRange linesRange = utils.getLinesRangeStatements(thenStatements);
2017 _addInsertEdit(thenBlockInsideOffset, source); 2133 String thenIndentOld = '$prefix$indent';
2134 String thenIndentNew = '$thenIndentOld$indent';
2135 builder.addSimpleReplacement(
2136 linesRange,
2137 utils.replaceSourceRangeIndent(
2138 linesRange, thenIndentOld, thenIndentNew));
2018 } 2139 }
2019 // insert closing "}" for inner "if" 2140 });
2020 { 2141 _addAssistFromBuilder(changeBuilder, DartAssistKind.SPLIT_AND_CONDITION);
2021 int thenBlockEnd = thenBlockRange.end;
2022 String source = "$indent}";
2023 // insert before outer "then" block "}"
2024 source += '$eol$prefix';
2025 _addInsertEdit(thenBlockEnd - 1, source);
2026 }
2027 } else {
2028 // insert inner "if" with right part of "condition"
2029 String source = '$eol$prefix${indent}if ($rightConditionSource)';
2030 _addInsertEdit(ifStatement.rightParenthesis.offset + 1, source);
2031 }
2032 // indent "then" statements to correspond inner "if"
2033 {
2034 List<Statement> thenStatements = getStatements(thenStatement);
2035 SourceRange linesRange = utils.getLinesRangeStatements(thenStatements);
2036 String thenIndentOld = '$prefix$indent';
2037 String thenIndentNew = '$thenIndentOld$indent';
2038 _addIndentEdit(linesRange, thenIndentOld, thenIndentNew);
2039 }
2040 // add proposal
2041 _addAssist(DartAssistKind.SPLIT_AND_CONDITION, []);
2042 } 2142 }
2043 2143
2044 void _addProposal_splitVariableDeclaration() { 2144 Future<Null> _addProposal_splitVariableDeclaration() async {
2045 // prepare DartVariableStatement, should be part of Block 2145 // prepare DartVariableStatement, should be part of Block
2046 VariableDeclarationStatement statement = 2146 VariableDeclarationStatement statement =
2047 node.getAncestor((node) => node is VariableDeclarationStatement); 2147 node.getAncestor((node) => node is VariableDeclarationStatement);
2048 if (statement != null && statement.parent is Block) {} else { 2148 if (statement != null && statement.parent is Block) {} else {
2049 _coverageMarker(); 2149 _coverageMarker();
2050 return; 2150 return;
2051 } 2151 }
2052 // check that statement declares single variable 2152 // check that statement declares single variable
2053 List<VariableDeclaration> variables = statement.variables.variables; 2153 List<VariableDeclaration> variables = statement.variables.variables;
2054 if (variables.length != 1) { 2154 if (variables.length != 1) {
2055 _coverageMarker(); 2155 _coverageMarker();
2056 return; 2156 return;
2057 } 2157 }
2058 VariableDeclaration variable = variables[0]; 2158 VariableDeclaration variable = variables[0];
2059 // prepare initializer 2159 // prepare initializer
2060 Expression initializer = variable.initializer; 2160 Expression initializer = variable.initializer;
2061 if (initializer == null) { 2161 if (initializer == null) {
2062 _coverageMarker(); 2162 _coverageMarker();
2063 return; 2163 return;
2064 } 2164 }
2065 // remove initializer value 2165 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2066 _addRemoveEdit(range.endStart(variable.name, statement.semicolon)); 2166 await changeBuilder.addFileEdit(file, fileStamp,
2067 // add assignment statement 2167 (DartFileEditBuilder builder) {
2068 String indent = utils.getNodePrefix(statement); 2168 // remove initializer value
2069 String name = variable.name.name; 2169 builder.addDeletion(range.endStart(variable.name, statement.semicolon));
2070 String initSrc = _getNodeText(initializer); 2170 // add assignment statement
2071 SourceRange assignRange = range.endLength(statement, 0); 2171 String indent = utils.getNodePrefix(statement);
2072 _addReplaceEdit(assignRange, eol + indent + name + ' = ' + initSrc + ';'); 2172 String name = variable.name.name;
2073 // add proposal 2173 String initSrc = _getNodeText(initializer);
2074 _addAssist(DartAssistKind.SPLIT_VARIABLE_DECLARATION, []); 2174 SourceRange assignRange = range.endLength(statement, 0);
2175 builder.addSimpleReplacement(
2176 assignRange, eol + indent + name + ' = ' + initSrc + ';');
2177 });
2178 _addAssistFromBuilder(
2179 changeBuilder, DartAssistKind.SPLIT_VARIABLE_DECLARATION);
2075 } 2180 }
2076 2181
2077 void _addProposal_surroundWith() { 2182 Future<Null> _addProposal_surroundWith() async {
2078 // prepare selected statements 2183 // prepare selected statements
2079 List<Statement> selectedStatements; 2184 List<Statement> selectedStatements;
2080 { 2185 {
2081 SourceRange selection = new SourceRange(selectionOffset, selectionLength); 2186 StatementAnalyzer selectionAnalyzer = new StatementAnalyzer(
2082 StatementAnalyzer selectionAnalyzer = 2187 unit, new SourceRange(selectionOffset, selectionLength));
2083 new StatementAnalyzer(unit, selection);
2084 unit.accept(selectionAnalyzer); 2188 unit.accept(selectionAnalyzer);
2085 List<AstNode> selectedNodes = selectionAnalyzer.selectedNodes; 2189 List<AstNode> selectedNodes = selectionAnalyzer.selectedNodes;
2086 // convert nodes to statements 2190 // convert nodes to statements
2087 selectedStatements = []; 2191 selectedStatements = [];
2088 for (AstNode selectedNode in selectedNodes) { 2192 for (AstNode selectedNode in selectedNodes) {
2089 if (selectedNode is Statement) { 2193 if (selectedNode is Statement) {
2090 selectedStatements.add(selectedNode); 2194 selectedStatements.add(selectedNode);
2091 } 2195 }
2092 } 2196 }
2093 // we want only statements 2197 // we want only statements
2094 if (selectedStatements.isEmpty || 2198 if (selectedStatements.isEmpty ||
2095 selectedStatements.length != selectedNodes.length) { 2199 selectedStatements.length != selectedNodes.length) {
2096 return; 2200 return;
2097 } 2201 }
2098 } 2202 }
2099 // prepare statement information 2203 // prepare statement information
2100 Statement firstStatement = selectedStatements[0]; 2204 Statement firstStatement = selectedStatements[0];
2101 Statement lastStatement = selectedStatements[selectedStatements.length - 1]; 2205 Statement lastStatement = selectedStatements[selectedStatements.length - 1];
2102 SourceRange statementsRange = 2206 SourceRange statementsRange =
2103 utils.getLinesRangeStatements(selectedStatements); 2207 utils.getLinesRangeStatements(selectedStatements);
2104 // prepare environment 2208 // prepare environment
2105 String indentOld = utils.getNodePrefix(firstStatement); 2209 String indentOld = utils.getNodePrefix(firstStatement);
2106 String indentNew = '$indentOld${utils.getIndent(1)}'; 2210 String indentNew = '$indentOld${utils.getIndent(1)}';
2107 String indentedCode = 2211 String indentedCode =
2108 utils.replaceSourceRangeIndent(statementsRange, indentOld, indentNew); 2212 utils.replaceSourceRangeIndent(statementsRange, indentOld, indentNew);
2109 // "block" 2213 // "block"
2110 { 2214 {
2111 _addInsertEdit(statementsRange.offset, '$indentOld{$eol'); 2215 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2112 _addIndentEdit(statementsRange, indentOld, indentNew); 2216 await changeBuilder.addFileEdit(file, fileStamp,
2113 _addInsertEdit(statementsRange.end, '$indentOld}$eol'); 2217 (DartFileEditBuilder builder) {
2114 exitPosition = _newPosition(lastStatement.end); 2218 builder.addSimpleInsertion(statementsRange.offset, '$indentOld{$eol');
2115 // add proposal 2219 builder.addSimpleReplacement(
2116 _addAssist(DartAssistKind.SURROUND_WITH_BLOCK, []); 2220 statementsRange,
2221 utils.replaceSourceRangeIndent(
2222 statementsRange, indentOld, indentNew));
2223 builder.addSimpleInsertion(statementsRange.end, '$indentOld}$eol');
2224 exitPosition = _newPosition(lastStatement.end);
2225 });
2226 _addAssistFromBuilder(changeBuilder, DartAssistKind.SURROUND_WITH_BLOCK);
2117 } 2227 }
2118 // "if" 2228 // "if"
2119 { 2229 {
2120 int offset = statementsRange.offset; 2230 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2121 SourceBuilder sb = new SourceBuilder(file, offset); 2231 await changeBuilder.addFileEdit(file, fileStamp,
2122 sb.append(indentOld); 2232 (DartFileEditBuilder builder) {
2123 sb.append('if ('); 2233 builder.addReplacement(statementsRange, (DartEditBuilder builder) {
2124 { 2234 builder.write(indentOld);
2125 sb.startPosition('CONDITION'); 2235 builder.write('if (');
2126 sb.append('condition'); 2236 builder.addSimpleLinkedEdit('CONDITION', 'condition');
2127 sb.endPosition(); 2237 builder.write(') {');
2128 } 2238 builder.write(eol);
2129 sb.append(') {'); 2239 builder.write(indentedCode);
2130 sb.append(eol); 2240 builder.write(indentOld);
2131 sb.append(indentedCode); 2241 builder.write('}');
2132 sb.append(indentOld); 2242 builder.selectHere();
2133 sb.append('}'); 2243 builder.write(eol);
2134 exitPosition = _newPosition(sb.offset + sb.length); 2244 });
2135 sb.append(eol); 2245 });
2136 _insertBuilder(sb, statementsRange.length); 2246 _addAssistFromBuilder(changeBuilder, DartAssistKind.SURROUND_WITH_IF);
2137 // add proposal
2138 _addAssist(DartAssistKind.SURROUND_WITH_IF, []);
2139 } 2247 }
2140 // "while" 2248 // "while"
2141 { 2249 {
2142 int offset = statementsRange.offset; 2250 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2143 SourceBuilder sb = new SourceBuilder(file, offset); 2251 await changeBuilder.addFileEdit(file, fileStamp,
2144 sb.append(indentOld); 2252 (DartFileEditBuilder builder) {
2145 sb.append('while ('); 2253 builder.addReplacement(statementsRange, (DartEditBuilder builder) {
2146 { 2254 builder.write(indentOld);
2147 sb.startPosition('CONDITION'); 2255 builder.write('while (');
2148 sb.append('condition'); 2256 builder.addSimpleLinkedEdit('CONDITION', 'condition');
2149 sb.endPosition(); 2257 builder.write(') {');
2150 } 2258 builder.write(eol);
2151 sb.append(') {'); 2259 builder.write(indentedCode);
2152 sb.append(eol); 2260 builder.write(indentOld);
2153 sb.append(indentedCode); 2261 builder.write('}');
2154 sb.append(indentOld); 2262 builder.selectHere();
2155 sb.append('}'); 2263 builder.write(eol);
2156 exitPosition = _newPosition(sb.offset + sb.length); 2264 });
2157 sb.append(eol); 2265 });
2158 _insertBuilder(sb, statementsRange.length); 2266 _addAssistFromBuilder(changeBuilder, DartAssistKind.SURROUND_WITH_WHILE);
2159 // add proposal
2160 _addAssist(DartAssistKind.SURROUND_WITH_WHILE, []);
2161 } 2267 }
2162 // "for-in" 2268 // "for-in"
2163 { 2269 {
2164 int offset = statementsRange.offset; 2270 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2165 SourceBuilder sb = new SourceBuilder(file, offset); 2271 await changeBuilder.addFileEdit(file, fileStamp,
2166 sb.append(indentOld); 2272 (DartFileEditBuilder builder) {
2167 sb.append('for (var '); 2273 builder.addReplacement(statementsRange, (DartEditBuilder builder) {
2168 { 2274 builder.write(indentOld);
2169 sb.startPosition('NAME'); 2275 builder.write('for (var ');
2170 sb.append('item'); 2276 builder.addSimpleLinkedEdit('NAME', 'item');
2171 sb.endPosition(); 2277 builder.write(' in ');
2172 } 2278 builder.addSimpleLinkedEdit('ITERABLE', 'iterable');
2173 sb.append(' in '); 2279 builder.write(') {');
2174 { 2280 builder.write(eol);
2175 sb.startPosition('ITERABLE'); 2281 builder.write(indentedCode);
2176 sb.append('iterable'); 2282 builder.write(indentOld);
2177 sb.endPosition(); 2283 builder.write('}');
2178 } 2284 builder.selectHere();
2179 sb.append(') {'); 2285 builder.write(eol);
2180 sb.append(eol); 2286 });
2181 sb.append(indentedCode); 2287 });
2182 sb.append(indentOld); 2288 _addAssistFromBuilder(changeBuilder, DartAssistKind.SURROUND_WITH_FOR_IN);
2183 sb.append('}');
2184 exitPosition = _newPosition(sb.offset + sb.length);
2185 sb.append(eol);
2186 _insertBuilder(sb, statementsRange.length);
2187 // add proposal
2188 _addAssist(DartAssistKind.SURROUND_WITH_FOR_IN, []);
2189 } 2289 }
2190 // "for" 2290 // "for"
2191 { 2291 {
2192 int offset = statementsRange.offset; 2292 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2193 SourceBuilder sb = new SourceBuilder(file, offset); 2293 await changeBuilder.addFileEdit(file, fileStamp,
2194 sb.append(indentOld); 2294 (DartFileEditBuilder builder) {
2195 sb.append('for (var '); 2295 builder.addReplacement(statementsRange, (DartEditBuilder builder) {
2196 { 2296 builder.write(indentOld);
2197 sb.startPosition('VAR'); 2297 builder.write('for (var ');
2198 sb.append('v'); 2298 builder.addSimpleLinkedEdit('VAR', 'v');
2199 sb.endPosition(); 2299 builder.write(' = ');
2200 } 2300 builder.addSimpleLinkedEdit('INIT', 'init');
2201 sb.append(' = '); 2301 builder.write('; ');
2202 { 2302 builder.addSimpleLinkedEdit('CONDITION', 'condition');
2203 sb.startPosition('INIT'); 2303 builder.write('; ');
2204 sb.append('init'); 2304 builder.addSimpleLinkedEdit('INCREMENT', 'increment');
2205 sb.endPosition(); 2305 builder.write(') {');
2206 } 2306 builder.write(eol);
2207 sb.append('; '); 2307 builder.write(indentedCode);
2208 { 2308 builder.write(indentOld);
2209 sb.startPosition('CONDITION'); 2309 builder.write('}');
2210 sb.append('condition'); 2310 builder.selectHere();
2211 sb.endPosition(); 2311 builder.write(eol);
2212 } 2312 });
2213 sb.append('; '); 2313 });
2214 { 2314 _addAssistFromBuilder(changeBuilder, DartAssistKind.SURROUND_WITH_FOR);
2215 sb.startPosition('INCREMENT');
2216 sb.append('increment');
2217 sb.endPosition();
2218 }
2219 sb.append(') {');
2220 sb.append(eol);
2221 sb.append(indentedCode);
2222 sb.append(indentOld);
2223 sb.append('}');
2224 exitPosition = _newPosition(sb.offset + sb.length);
2225 sb.append(eol);
2226 _insertBuilder(sb, statementsRange.length);
2227 // add proposal
2228 _addAssist(DartAssistKind.SURROUND_WITH_FOR, []);
2229 } 2315 }
2230 // "do-while" 2316 // "do-while"
2231 { 2317 {
2232 int offset = statementsRange.offset; 2318 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2233 SourceBuilder sb = new SourceBuilder(file, offset); 2319 await changeBuilder.addFileEdit(file, fileStamp,
2234 sb.append(indentOld); 2320 (DartFileEditBuilder builder) {
2235 sb.append('do {'); 2321 builder.addReplacement(statementsRange, (DartEditBuilder builder) {
2236 sb.append(eol); 2322 builder.write(indentOld);
2237 sb.append(indentedCode); 2323 builder.write('do {');
2238 sb.append(indentOld); 2324 builder.write(eol);
2239 sb.append('} while ('); 2325 builder.write(indentedCode);
2240 { 2326 builder.write(indentOld);
2241 sb.startPosition('CONDITION'); 2327 builder.write('} while (');
2242 sb.append('condition'); 2328 builder.addSimpleLinkedEdit('CONDITION', 'condition');
2243 sb.endPosition(); 2329 builder.write(');');
2244 } 2330 builder.selectHere();
2245 sb.append(');'); 2331 builder.write(eol);
2246 exitPosition = _newPosition(sb.offset + sb.length); 2332 });
2247 sb.append(eol); 2333 });
2248 _insertBuilder(sb, statementsRange.length); 2334 _addAssistFromBuilder(
2249 // add proposal 2335 changeBuilder, DartAssistKind.SURROUND_WITH_DO_WHILE);
2250 _addAssist(DartAssistKind.SURROUND_WITH_DO_WHILE, []);
2251 } 2336 }
2252 // "try-catch" 2337 // "try-catch"
2253 { 2338 {
2254 int offset = statementsRange.offset; 2339 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2255 SourceBuilder sb = new SourceBuilder(file, offset); 2340 await changeBuilder.addFileEdit(file, fileStamp,
2256 sb.append(indentOld); 2341 (DartFileEditBuilder builder) {
2257 sb.append('try {'); 2342 builder.addReplacement(statementsRange, (DartEditBuilder builder) {
2258 sb.append(eol); 2343 builder.write(indentOld);
2259 sb.append(indentedCode); 2344 builder.write('try {');
2260 sb.append(indentOld); 2345 builder.write(eol);
2261 sb.append('} on '); 2346 builder.write(indentedCode);
2262 { 2347 builder.write(indentOld);
2263 sb.startPosition('EXCEPTION_TYPE'); 2348 builder.write('} on ');
2264 sb.append('Exception'); 2349 builder.addSimpleLinkedEdit('EXCEPTION_TYPE', 'Exception');
2265 sb.endPosition(); 2350 builder.write(' catch (');
2266 } 2351 builder.addSimpleLinkedEdit('EXCEPTION_VAR', 'e');
2267 sb.append(' catch ('); 2352 builder.write(') {');
2268 { 2353 builder.write(eol);
2269 sb.startPosition('EXCEPTION_VAR'); 2354 //
2270 sb.append('e'); 2355 builder.write(indentNew);
2271 sb.endPosition(); 2356 builder.addSimpleLinkedEdit('CATCH', '// TODO');
2272 } 2357 builder.selectHere();
2273 sb.append(') {'); 2358 builder.write(eol);
2274 sb.append(eol); 2359 //
2275 // 2360 builder.write(indentOld);
2276 sb.append(indentNew); 2361 builder.write('}');
2277 { 2362 builder.write(eol);
2278 sb.startPosition('CATCH'); 2363 });
2279 sb.append('// TODO'); 2364 });
2280 sb.endPosition(); 2365 _addAssistFromBuilder(
2281 sb.setExitOffset(); 2366 changeBuilder, DartAssistKind.SURROUND_WITH_TRY_CATCH);
2282 }
2283 sb.append(eol);
2284 //
2285 sb.append(indentOld);
2286 sb.append('}');
2287 sb.append(eol);
2288 _insertBuilder(sb, statementsRange.length);
2289 // add proposal
2290 _addAssist(DartAssistKind.SURROUND_WITH_TRY_CATCH, []);
2291 } 2367 }
2292 // "try-finally" 2368 // "try-finally"
2293 { 2369 {
2294 int offset = statementsRange.offset; 2370 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2295 SourceBuilder sb = new SourceBuilder(file, offset); 2371 await changeBuilder.addFileEdit(file, fileStamp,
2296 // 2372 (DartFileEditBuilder builder) {
2297 sb.append(indentOld); 2373 builder.addReplacement(statementsRange, (DartEditBuilder builder) {
2298 sb.append('try {'); 2374 builder.write(indentOld);
2299 sb.append(eol); 2375 builder.write('try {');
2300 // 2376 builder.write(eol);
2301 sb.append(indentedCode); 2377 //
2302 // 2378 builder.write(indentedCode);
2303 sb.append(indentOld); 2379 //
2304 sb.append('} finally {'); 2380 builder.write(indentOld);
2305 sb.append(eol); 2381 builder.write('} finally {');
2306 // 2382 builder.write(eol);
2307 sb.append(indentNew); 2383 //
2308 { 2384 builder.write(indentNew);
2309 sb.startPosition('FINALLY'); 2385 builder.addSimpleLinkedEdit('FINALLY', '// TODO');
2310 sb.append('// TODO'); 2386 builder.selectHere();
2311 sb.endPosition(); 2387 builder.write(eol);
2312 sb.setExitOffset(); 2388 //
2313 } 2389 builder.write(indentOld);
2314 sb.setExitOffset(); 2390 builder.write('}');
2315 sb.append(eol); 2391 builder.write(eol);
2316 // 2392 });
2317 sb.append(indentOld); 2393 });
2318 sb.append('}'); 2394 _addAssistFromBuilder(
2319 sb.append(eol); 2395 changeBuilder, DartAssistKind.SURROUND_WITH_TRY_FINALLY);
2320 //
2321 _insertBuilder(sb, statementsRange.length);
2322 // add proposal
2323 _addAssist(DartAssistKind.SURROUND_WITH_TRY_FINALLY, []);
2324 } 2396 }
2325 } 2397 }
2326 2398
2327 /** 2399 /**
2328 * Adds a new [Edit] to [edits].
2329 */
2330 void _addRemoveEdit(SourceRange range) {
2331 _addReplaceEdit(range, '');
2332 }
2333
2334 /**
2335 * Adds a new [SourceEdit] to [edits].
2336 */
2337 void _addReplaceEdit(SourceRange range, String text) {
2338 SourceEdit edit = new SourceEdit(range.offset, range.length, text);
2339 doSourceChange_addElementEdit(change, unitElement, edit);
2340 }
2341
2342 /**
2343 * Configures [utils] using given [target]. 2400 * Configures [utils] using given [target].
2344 */ 2401 */
2345 void _configureTargetLocation(Object target) { 2402 void _configureTargetLocation(Object target) {
2346 utils.targetClassElement = null; 2403 utils.targetClassElement = null;
2347 if (target is AstNode) { 2404 if (target is AstNode) {
2348 ClassDeclaration targetClassDeclaration = 2405 ClassDeclaration targetClassDeclaration =
2349 target.getAncestor((node) => node is ClassDeclaration); 2406 target.getAncestor((node) => node is ClassDeclaration);
2350 if (targetClassDeclaration != null) { 2407 if (targetClassDeclaration != null) {
2351 utils.targetClassElement = targetClassDeclaration.element; 2408 utils.targetClassElement = targetClassDeclaration.element;
2352 } 2409 }
2353 } 2410 }
2354 } 2411 }
2355 2412
2413 void _convertFlutterChildToChildren(
2414 InstanceCreationExpression childArg,
2415 NamedExpression namedExp,
2416 String eol,
2417 Function getNodeText,
2418 Function getLinePrefix,
2419 Function getIndent,
2420 Function getText,
2421 DartFileEditBuilder builder) {
2422 int childLoc = namedExp.offset + 'child'.length;
2423 builder.addSimpleInsertion(childLoc, 'ren');
2424 int listLoc = childArg.offset;
2425 String childArgSrc = getNodeText(childArg);
2426 if (!childArgSrc.contains(eol)) {
2427 builder.addSimpleInsertion(listLoc, '<Widget>[');
2428 builder.addSimpleInsertion(listLoc + childArg.length, ']');
2429 } else {
2430 int newlineLoc = childArgSrc.lastIndexOf(eol);
2431 if (newlineLoc == childArgSrc.length) {
2432 newlineLoc -= 1;
2433 }
2434 String indentOld = getLinePrefix(childArg.offset + 1 + newlineLoc);
2435 String indentNew = '$indentOld${getIndent(1)}';
2436 // The separator includes 'child:' but that has no newlines.
2437 String separator =
2438 getText(namedExp.offset, childArg.offset - namedExp.offset);
2439 String prefix = separator.contains(eol) ? "" : "$eol$indentNew";
2440 if (prefix.isEmpty) {
2441 builder.addSimpleInsertion(
2442 namedExp.offset + 'child:'.length, ' <Widget>[');
2443 int argOffset = childArg.offset;
2444 builder
2445 .addDeletion(range.startOffsetEndOffset(argOffset - 2, argOffset));
2446 } else {
2447 builder.addSimpleInsertion(listLoc, '<Widget>[');
2448 }
2449 String newChildArgSrc = childArgSrc.replaceAll(
2450 new RegExp("^$indentOld", multiLine: true), "$indentNew");
2451 newChildArgSrc = "$prefix$newChildArgSrc,$eol$indentOld]";
2452 builder.addSimpleReplacement(range.node(childArg), newChildArgSrc);
2453 }
2454 }
2455
2356 /** 2456 /**
2357 * Returns an existing or just added [LinkedEditGroup] with [groupId].
2358 */
2359 LinkedEditGroup _getLinkedPosition(String groupId) {
2360 LinkedEditGroup group = linkedPositionGroups[groupId];
2361 if (group == null) {
2362 group = new LinkedEditGroup.empty();
2363 linkedPositionGroups[groupId] = group;
2364 }
2365 return group;
2366 }
2367
2368 /**
2369 * Returns the text of the given node in the unit. 2457 * Returns the text of the given node in the unit.
2370 */ 2458 */
2371 String _getNodeText(AstNode node) { 2459 String _getNodeText(AstNode node) {
2372 return utils.getNodeText(node); 2460 return utils.getNodeText(node);
2373 } 2461 }
2374 2462
2375 /** 2463 /**
2376 * Returns the text of the given range in the unit. 2464 * Returns the text of the given range in the unit.
2377 */ 2465 */
2378 String _getRangeText(SourceRange range) { 2466 String _getRangeText(SourceRange range) {
2379 return utils.getRangeText(range); 2467 return utils.getRangeText(range);
2380 } 2468 }
2381 2469
2382 /**
2383 * Inserts the given [SourceBuilder] at its offset.
2384 */
2385 void _insertBuilder(SourceBuilder builder, [int length = 0]) {
2386 {
2387 SourceRange range = new SourceRange(builder.offset, length);
2388 String text = builder.toString();
2389 _addReplaceEdit(range, text);
2390 }
2391 // add linked positions
2392 builder.linkedPositionGroups.forEach((String id, LinkedEditGroup group) {
2393 LinkedEditGroup fixGroup = _getLinkedPosition(id);
2394 group.positions.forEach((Position position) {
2395 fixGroup.addPosition(position, group.length);
2396 });
2397 group.suggestions.forEach((LinkedEditSuggestion suggestion) {
2398 fixGroup.addSuggestion(suggestion);
2399 });
2400 });
2401 // add exit position
2402 {
2403 int exitOffset = builder.exitOffset;
2404 if (exitOffset != null) {
2405 exitPosition = _newPosition(exitOffset);
2406 }
2407 }
2408 }
2409
2410 int _modificationStamp(String filePath) { 2470 int _modificationStamp(String filePath) {
2411 // TODO(brianwilkerson) We have lost the ability for clients to know whether 2471 // TODO(brianwilkerson) We have lost the ability for clients to know whether
2412 // it is safe to apply an edit. 2472 // it is safe to apply an edit.
2413 return driver.fsState.getFileForPath(filePath).exists ? 0 : -1; 2473 return driver.fsState.getFileForPath(filePath).exists ? 0 : -1;
2414 } 2474 }
2415 2475
2416 Position _newPosition(int offset) { 2476 Position _newPosition(int offset) {
2417 return new Position(file, offset); 2477 return new Position(file, offset);
2418 } 2478 }
2419 2479
2420 void _swapFlutterWidgets( 2480 Future<Null> _swapFlutterWidgets(
2421 InstanceCreationExpression exprGoingDown, 2481 InstanceCreationExpression exprGoingDown,
2422 InstanceCreationExpression exprGoingUp, 2482 InstanceCreationExpression exprGoingUp,
2423 NamedExpression stableChild, 2483 NamedExpression stableChild,
2424 AssistKind assistKind) { 2484 AssistKind assistKind) async {
2425 String currentSource = unitElement.context.getContents(source).data; 2485 String currentSource = unitElement.context.getContents(source).data;
2426 // TODO(messick) Find a better way to get LineInfo for the source. 2486 // TODO(messick) Find a better way to get LineInfo for the source.
2427 LineInfo lineInfo = new LineInfo.fromContent(currentSource); 2487 LineInfo lineInfo = new LineInfo.fromContent(currentSource);
2428 int currLn = lineInfo.getLocation(exprGoingUp.offset).lineNumber; 2488 int currLn = lineInfo.getLocation(exprGoingUp.offset).lineNumber;
2429 int lnOffset = lineInfo.getOffsetOfLine(currLn); 2489 int lnOffset = lineInfo.getOffsetOfLine(currLn);
2430 SourceBuilder sb = new SourceBuilder(file, exprGoingDown.offset);
2431 String argSrc =
2432 utils.getText(exprGoingUp.offset, lnOffset - exprGoingUp.offset);
2433 sb.append(argSrc); // Append child new-expr plus rest of line.
2434 2490
2435 String getSrc(Expression expr) { 2491 DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
2436 int startLn = lineInfo.getLocation(expr.offset).lineNumber; 2492 await changeBuilder.addFileEdit(file, fileStamp,
2437 int startOffset = lineInfo.getOffsetOfLine(startLn - 1); 2493 (DartFileEditBuilder builder) {
2438 int endLn = 2494 builder.addReplacement(range.node(exprGoingDown),
2439 lineInfo.getLocation(expr.offset + expr.length).lineNumber + 1; 2495 (DartEditBuilder builder) {
2440 int curOffset = lineInfo.getOffsetOfLine(endLn - 1); 2496 String argSrc =
2441 return utils.getText(startOffset, curOffset - startOffset); 2497 utils.getText(exprGoingUp.offset, lnOffset - exprGoingUp.offset);
2442 } 2498 builder.write(argSrc); // Append child new-expr plus rest of line.
2443 2499
2444 String outerIndent = utils.getNodePrefix(exprGoingDown.parent); 2500 String getSrc(Expression expr) {
2445 String innerIndent = utils.getNodePrefix(exprGoingUp.parent); 2501 int startLn = lineInfo.getLocation(expr.offset).lineNumber;
2446 exprGoingUp.argumentList.arguments.forEach((arg) { 2502 int startOffset = lineInfo.getOffsetOfLine(startLn - 1);
2447 if (arg is NamedExpression && arg.name.label.name == 'child') { 2503 int endLn =
2448 if (stableChild != arg) { 2504 lineInfo.getLocation(expr.offset + expr.length).lineNumber + 1;
2449 _coverageMarker(); 2505 int curOffset = lineInfo.getOffsetOfLine(endLn - 1);
2450 return; 2506 return utils.getText(startOffset, curOffset - startOffset);
2451 } 2507 }
2452 // Insert exprGoingDown here.
2453 // Copy from start of line to offset of exprGoingDown.
2454 currLn = lineInfo.getLocation(stableChild.offset).lineNumber;
2455 lnOffset = lineInfo.getOffsetOfLine(currLn - 1);
2456 argSrc =
2457 utils.getText(lnOffset, stableChild.expression.offset - lnOffset);
2458 argSrc = argSrc.replaceAll(
2459 new RegExp("^$innerIndent", multiLine: true), "$outerIndent");
2460 sb.append(argSrc);
2461 int nextLn = lineInfo.getLocation(exprGoingDown.offset).lineNumber;
2462 lnOffset = lineInfo.getOffsetOfLine(nextLn);
2463 argSrc = utils.getText(
2464 exprGoingDown.offset, lnOffset - exprGoingDown.offset);
2465 sb.append(argSrc);
2466 2508
2467 exprGoingDown.argumentList.arguments.forEach((val) { 2509 String outerIndent = utils.getNodePrefix(exprGoingDown.parent);
2468 if (val is NamedExpression && val.name.label.name == 'child') { 2510 String innerIndent = utils.getNodePrefix(exprGoingUp.parent);
2469 // Insert stableChild here at same indent level. 2511 exprGoingUp.argumentList.arguments.forEach((arg) {
2470 sb.append(utils.getNodePrefix(arg.name)); 2512 if (arg is NamedExpression && arg.name.label.name == 'child') {
2471 argSrc = utils.getNodeText(stableChild); 2513 if (stableChild != arg) {
2472 sb.append(argSrc); 2514 _coverageMarker();
2473 if (assistKind == DartAssistKind.MOVE_FLUTTER_WIDGET_UP) { 2515 return;
2474 sb.append(',$eol');
2475 } 2516 }
2517 // Insert exprGoingDown here.
2518 // Copy from start of line to offset of exprGoingDown.
2519 currLn = lineInfo.getLocation(stableChild.offset).lineNumber;
2520 lnOffset = lineInfo.getOffsetOfLine(currLn - 1);
2521 argSrc = utils.getText(
2522 lnOffset, stableChild.expression.offset - lnOffset);
2523 argSrc = argSrc.replaceAll(
2524 new RegExp("^$innerIndent", multiLine: true), "$outerIndent");
2525 builder.write(argSrc);
2526 int nextLn = lineInfo.getLocation(exprGoingDown.offset).lineNumber;
2527 lnOffset = lineInfo.getOffsetOfLine(nextLn);
2528 argSrc = utils.getText(
2529 exprGoingDown.offset, lnOffset - exprGoingDown.offset);
2530 builder.write(argSrc);
2531
2532 exprGoingDown.argumentList.arguments.forEach((val) {
2533 if (val is NamedExpression && val.name.label.name == 'child') {
2534 // Insert stableChild here at same indent level.
2535 builder.write(utils.getNodePrefix(arg.name));
2536 argSrc = utils.getNodeText(stableChild);
2537 builder.write(argSrc);
2538 if (assistKind == DartAssistKind.MOVE_FLUTTER_WIDGET_UP) {
2539 builder.write(',$eol');
2540 }
2541 } else {
2542 argSrc = getSrc(val);
2543 argSrc = argSrc.replaceAll(
2544 new RegExp("^$outerIndent", multiLine: true),
2545 "$innerIndent");
2546 builder.write(argSrc);
2547 }
2548 });
2549 if (assistKind == DartAssistKind.MOVE_FLUTTER_WIDGET_DOWN) {
2550 builder.write(',$eol');
2551 }
2552 builder.write(innerIndent);
2553 builder.write('),$eol');
2476 } else { 2554 } else {
2477 argSrc = getSrc(val); 2555 argSrc = getSrc(arg);
2478 argSrc = argSrc.replaceAll( 2556 argSrc = argSrc.replaceAll(
2479 new RegExp("^$outerIndent", multiLine: true), "$innerIndent"); 2557 new RegExp("^$innerIndent", multiLine: true), "$outerIndent");
2480 sb.append(argSrc); 2558 builder.write(argSrc);
2481 } 2559 }
2482 }); 2560 });
2483 if (assistKind == DartAssistKind.MOVE_FLUTTER_WIDGET_DOWN) { 2561 builder.write(outerIndent);
2484 sb.append(',$eol'); 2562 builder.write(')');
2485 } 2563 builder.selectHere();
2486 sb.append(innerIndent); 2564 });
2487 sb.append('),$eol');
2488 } else {
2489 argSrc = getSrc(arg);
2490 argSrc = argSrc.replaceAll(
2491 new RegExp("^$innerIndent", multiLine: true), "$outerIndent");
2492 sb.append(argSrc);
2493 }
2494 }); 2565 });
2495 sb.append(outerIndent); 2566 _addAssistFromBuilder(changeBuilder, assistKind);
2496 sb.append(')');
2497
2498 exitPosition = _newPosition(sb.offset + sb.length);
2499 _insertBuilder(sb, exprGoingDown.length);
2500 _addAssist(assistKind, []);
2501 } 2567 }
2502 2568
2503 /** 2569 /**
2504 * This method does nothing, but we invoke it in places where Dart VM 2570 * This method does nothing, but we invoke it in places where Dart VM
2505 * coverage agent fails to provide coverage information - such as almost 2571 * coverage agent fails to provide coverage information - such as almost
2506 * all "return" statements. 2572 * all "return" statements.
2507 * 2573 *
2508 * https://code.google.com/p/dart/issues/detail?id=19912 2574 * https://code.google.com/p/dart/issues/detail?id=19912
2509 */ 2575 */
2510 static void _coverageMarker() {} 2576 static void _coverageMarker() {}
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
2568 class _SimpleIdentifierRecursiveAstVisitor extends RecursiveAstVisitor { 2634 class _SimpleIdentifierRecursiveAstVisitor extends RecursiveAstVisitor {
2569 final _SimpleIdentifierVisitor visitor; 2635 final _SimpleIdentifierVisitor visitor;
2570 2636
2571 _SimpleIdentifierRecursiveAstVisitor(this.visitor); 2637 _SimpleIdentifierRecursiveAstVisitor(this.visitor);
2572 2638
2573 @override 2639 @override
2574 visitSimpleIdentifier(SimpleIdentifier node) { 2640 visitSimpleIdentifier(SimpleIdentifier node) {
2575 visitor(node); 2641 visitor(node);
2576 } 2642 }
2577 } 2643 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698