| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library services.src.completion.statement; | 5 library services.src.completion.statement; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/protocol/protocol_generated.dart'; | 9 import 'package:analysis_server/protocol/protocol_generated.dart'; |
| 10 import 'package:analysis_server/src/protocol_server.dart' hide Element; | 10 import 'package:analysis_server/src/protocol_server.dart' hide Element; |
| 11 import 'package:analysis_server/src/services/correction/source_buffer.dart'; | 11 import 'package:analysis_server/src/services/correction/source_buffer.dart'; |
| 12 import 'package:analysis_server/src/services/correction/source_range.dart'; | |
| 13 import 'package:analysis_server/src/services/correction/util.dart'; | 12 import 'package:analysis_server/src/services/correction/util.dart'; |
| 14 import 'package:analyzer/dart/ast/ast.dart'; | 13 import 'package:analyzer/dart/ast/ast.dart'; |
| 15 import 'package:analyzer/dart/ast/token.dart'; | 14 import 'package:analyzer/dart/ast/token.dart'; |
| 16 import 'package:analyzer/dart/element/element.dart'; | 15 import 'package:analyzer/dart/element/element.dart'; |
| 17 import 'package:analyzer/error/error.dart'; | 16 import 'package:analyzer/error/error.dart'; |
| 18 import 'package:analyzer/error/error.dart' as engine; | 17 import 'package:analyzer/error/error.dart' as engine; |
| 19 import 'package:analyzer/src/dart/ast/utilities.dart'; | 18 import 'package:analyzer/src/dart/ast/utilities.dart'; |
| 20 import 'package:analyzer/src/dart/error/hint_codes.dart'; | 19 import 'package:analyzer/src/dart/error/hint_codes.dart'; |
| 21 import 'package:analyzer/src/dart/error/syntactic_errors.dart'; | 20 import 'package:analyzer/src/dart/error/syntactic_errors.dart'; |
| 22 import 'package:analyzer/src/generated/engine.dart'; | 21 import 'package:analyzer/src/generated/engine.dart'; |
| 23 import 'package:analyzer/src/generated/java_core.dart'; | 22 import 'package:analyzer/src/generated/java_core.dart'; |
| 24 import 'package:analyzer/src/generated/source.dart'; | 23 import 'package:analyzer/src/generated/source.dart'; |
| 24 import 'package:analyzer_plugin/utilities/range_factory.dart'; |
| 25 | 25 |
| 26 /** | 26 /** |
| 27 * An enumeration of possible statement completion kinds. | 27 * An enumeration of possible statement completion kinds. |
| 28 */ | 28 */ |
| 29 class DartStatementCompletion { | 29 class DartStatementCompletion { |
| 30 static const NO_COMPLETION = | 30 static const NO_COMPLETION = |
| 31 const StatementCompletionKind('No_COMPLETION', 'No completion available'); | 31 const StatementCompletionKind('No_COMPLETION', 'No completion available'); |
| 32 static const SIMPLE_ENTER = const StatementCompletionKind( | 32 static const SIMPLE_ENTER = const StatementCompletionKind( |
| 33 'SIMPLE_ENTER', "Insert a newline at the end of the current line"); | 33 'SIMPLE_ENTER', "Insert a newline at the end of the current line"); |
| 34 static const SIMPLE_SEMICOLON = const StatementCompletionKind( | 34 static const SIMPLE_SEMICOLON = const StatementCompletionKind( |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 } | 360 } |
| 361 DoStatement statement = node; | 361 DoStatement statement = node; |
| 362 SourceBuilder sb = _sourceBuilderAfterKeyword(statement.doKeyword); | 362 SourceBuilder sb = _sourceBuilderAfterKeyword(statement.doKeyword); |
| 363 bool hasWhileKeyword = statement.whileKeyword.lexeme == "while"; | 363 bool hasWhileKeyword = statement.whileKeyword.lexeme == "while"; |
| 364 int exitDelta = 0; | 364 int exitDelta = 0; |
| 365 if (!_statementHasValidBody(statement.doKeyword, statement.body)) { | 365 if (!_statementHasValidBody(statement.doKeyword, statement.body)) { |
| 366 String text = utils.getNodeText(statement.body); | 366 String text = utils.getNodeText(statement.body); |
| 367 int delta = 0; | 367 int delta = 0; |
| 368 if (text.startsWith(';')) { | 368 if (text.startsWith(';')) { |
| 369 delta = 1; | 369 delta = 1; |
| 370 _addReplaceEdit(rangeStartLength(statement.body.offset, delta), ''); | 370 _addReplaceEdit(range.startLength(statement.body, delta), ''); |
| 371 if (hasWhileKeyword) { | 371 if (hasWhileKeyword) { |
| 372 text = utils.getNodeText(statement); | 372 text = utils.getNodeText(statement); |
| 373 if (text.indexOf(new RegExp(r'do\s*;\s*while')) == 0) { | 373 if (text.indexOf(new RegExp(r'do\s*;\s*while')) == 0) { |
| 374 int end = text.indexOf('while'); | 374 int end = text.indexOf('while'); |
| 375 int start = text.indexOf(';') + 1; | 375 int start = text.indexOf(';') + 1; |
| 376 delta += end - start - 1; | 376 delta += end - start - 1; |
| 377 _addReplaceEdit( | 377 _addReplaceEdit( |
| 378 rangeStartLength(start + statement.offset, end - start), ' '); | 378 new SourceRange(start + statement.offset, end - start), ' '); |
| 379 } | 379 } |
| 380 } | 380 } |
| 381 sb = new SourceBuilder(file, sb.offset + delta); | 381 sb = new SourceBuilder(file, sb.offset + delta); |
| 382 sb.append(' '); | 382 sb.append(' '); |
| 383 } | 383 } |
| 384 _appendEmptyBraces(sb, | 384 _appendEmptyBraces(sb, |
| 385 !(hasWhileKeyword && _isSyntheticExpression(statement.condition))); | 385 !(hasWhileKeyword && _isSyntheticExpression(statement.condition))); |
| 386 if (delta != 0) { | 386 if (delta != 0) { |
| 387 exitDelta = sb.length - delta; | 387 exitDelta = sb.length - delta; |
| 388 } | 388 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 SourceBuilder sb = | 444 SourceBuilder sb = |
| 445 new SourceBuilder(file, forNode.rightParenthesis.offset + 1); | 445 new SourceBuilder(file, forNode.rightParenthesis.offset + 1); |
| 446 AstNode name = forNode.identifier; | 446 AstNode name = forNode.identifier; |
| 447 name ??= forNode.loopVariable; | 447 name ??= forNode.loopVariable; |
| 448 String src = utils.getNodeText(forNode); | 448 String src = utils.getNodeText(forNode); |
| 449 if (name == null) { | 449 if (name == null) { |
| 450 exitPosition = new Position(file, forNode.leftParenthesis.offset + 1); | 450 exitPosition = new Position(file, forNode.leftParenthesis.offset + 1); |
| 451 src = src.substring(forNode.leftParenthesis.offset - forNode.offset); | 451 src = src.substring(forNode.leftParenthesis.offset - forNode.offset); |
| 452 if (src.startsWith(new RegExp(r'\(\s*in\s*\)'))) { | 452 if (src.startsWith(new RegExp(r'\(\s*in\s*\)'))) { |
| 453 _addReplaceEdit( | 453 _addReplaceEdit( |
| 454 rangeStartEnd(forNode.leftParenthesis.offset + 1, | 454 range.offsetEndIndex(forNode.leftParenthesis.offset + 1, |
| 455 forNode.rightParenthesis.offset), | 455 forNode.rightParenthesis.offset), |
| 456 ' in '); | 456 ' in '); |
| 457 } else if (src.startsWith(new RegExp(r'\(\s*in'))) { | 457 } else if (src.startsWith(new RegExp(r'\(\s*in'))) { |
| 458 _addReplaceEdit( | 458 _addReplaceEdit( |
| 459 rangeStartEnd( | 459 range.offsetEndIndex( |
| 460 forNode.leftParenthesis.offset + 1, forNode.inKeyword.offset), | 460 forNode.leftParenthesis.offset + 1, forNode.inKeyword.offset), |
| 461 ' '); | 461 ' '); |
| 462 } | 462 } |
| 463 } else if (_isSyntheticExpression(forNode.iterable)) { | 463 } else if (_isSyntheticExpression(forNode.iterable)) { |
| 464 exitPosition = new Position(file, forNode.rightParenthesis.offset + 1); | 464 exitPosition = new Position(file, forNode.rightParenthesis.offset + 1); |
| 465 src = src.substring(forNode.inKeyword.offset - forNode.offset); | 465 src = src.substring(forNode.inKeyword.offset - forNode.offset); |
| 466 if (src.startsWith(new RegExp(r'in\s*\)'))) { | 466 if (src.startsWith(new RegExp(r'in\s*\)'))) { |
| 467 _addReplaceEdit( | 467 _addReplaceEdit( |
| 468 rangeStartEnd(forNode.inKeyword.offset + forNode.inKeyword.length, | 468 range.offsetEndIndex( |
| 469 forNode.inKeyword.offset + forNode.inKeyword.length, |
| 469 forNode.rightParenthesis.offset), | 470 forNode.rightParenthesis.offset), |
| 470 ' '); | 471 ' '); |
| 471 } | 472 } |
| 472 } | 473 } |
| 473 if (!_statementHasValidBody(forNode.forKeyword, forNode.body)) { | 474 if (!_statementHasValidBody(forNode.forKeyword, forNode.body)) { |
| 474 sb.append(' '); | 475 sb.append(' '); |
| 475 _appendEmptyBraces(sb, exitPosition == null); | 476 _appendEmptyBraces(sb, exitPosition == null); |
| 476 } | 477 } |
| 477 _insertBuilder(sb); | 478 _insertBuilder(sb); |
| 478 _setCompletion(DartStatementCompletion.COMPLETE_FOR_EACH_STMT); | 479 _setCompletion(DartStatementCompletion.COMPLETE_FOR_EACH_STMT); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 503 } else if (!forNode.leftSeparator.isSynthetic) { | 504 } else if (!forNode.leftSeparator.isSynthetic) { |
| 504 if (_isSyntheticExpression(forNode.condition)) { | 505 if (_isSyntheticExpression(forNode.condition)) { |
| 505 exitPosition = _newPosition(forNode.leftSeparator.offset + 1); | 506 exitPosition = _newPosition(forNode.leftSeparator.offset + 1); |
| 506 String text = utils | 507 String text = utils |
| 507 .getNodeText(forNode) | 508 .getNodeText(forNode) |
| 508 .substring(forNode.leftSeparator.offset - forNode.offset); | 509 .substring(forNode.leftSeparator.offset - forNode.offset); |
| 509 if (text.startsWith(new RegExp(r';\s*\)'))) { | 510 if (text.startsWith(new RegExp(r';\s*\)'))) { |
| 510 // emptyCondition | 511 // emptyCondition |
| 511 int end = text.indexOf(')'); | 512 int end = text.indexOf(')'); |
| 512 sb = new SourceBuilder(file, forNode.leftSeparator.offset); | 513 sb = new SourceBuilder(file, forNode.leftSeparator.offset); |
| 513 _addReplaceEdit(rangeStartLength(sb.offset, end), '; ; '); | 514 _addReplaceEdit(new SourceRange(sb.offset, end), '; ; '); |
| 514 delta = end - '; '.length; | 515 delta = end - '; '.length; |
| 515 } else { | 516 } else { |
| 516 // emptyInitializersEmptyCondition | 517 // emptyInitializersEmptyCondition |
| 517 exitPosition = _newPosition(forNode.rightParenthesis.offset); | 518 exitPosition = _newPosition(forNode.rightParenthesis.offset); |
| 518 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); | 519 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); |
| 519 } | 520 } |
| 520 } else { | 521 } else { |
| 521 // emptyUpdaters | 522 // emptyUpdaters |
| 522 exitPosition = _newPosition(forNode.rightSeparator.offset); | 523 exitPosition = _newPosition(forNode.rightSeparator.offset); |
| 523 sb = new SourceBuilder(file, forNode.rightSeparator.offset); | 524 sb = new SourceBuilder(file, forNode.rightSeparator.offset); |
| 524 _addReplaceEdit(rangeStartLength(sb.offset, 0), '; '); | 525 _addReplaceEdit(new SourceRange(sb.offset, 0), '; '); |
| 525 delta = -'; '.length; | 526 delta = -'; '.length; |
| 526 } | 527 } |
| 527 } else if (_isSyntheticExpression(forNode.initialization)) { | 528 } else if (_isSyntheticExpression(forNode.initialization)) { |
| 528 // emptyInitializers | 529 // emptyInitializers |
| 529 exitPosition = _newPosition(forNode.rightParenthesis.offset); | 530 exitPosition = _newPosition(forNode.rightParenthesis.offset); |
| 530 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); | 531 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); |
| 531 } else { | 532 } else { |
| 532 int start = forNode.condition.offset + forNode.condition.length; | 533 int start = forNode.condition.offset + forNode.condition.length; |
| 533 String text = | 534 String text = |
| 534 utils.getNodeText(forNode).substring(start - forNode.offset); | 535 utils.getNodeText(forNode).substring(start - forNode.offset); |
| 535 if (text.startsWith(new RegExp(r'\s*\)'))) { | 536 if (text.startsWith(new RegExp(r'\s*\)'))) { |
| 536 // missingLeftSeparator | 537 // missingLeftSeparator |
| 537 int end = text.indexOf(')'); | 538 int end = text.indexOf(')'); |
| 538 sb = new SourceBuilder(file, start); | 539 sb = new SourceBuilder(file, start); |
| 539 _addReplaceEdit(rangeStartLength(start, end), '; '); | 540 _addReplaceEdit(new SourceRange(start, end), '; '); |
| 540 delta = end - '; '.length; | 541 delta = end - '; '.length; |
| 541 exitPosition = new Position(file, start); | 542 exitPosition = new Position(file, start); |
| 542 } else { | 543 } else { |
| 543 // Not possible; any comment following init is attached to init. | 544 // Not possible; any comment following init is attached to init. |
| 544 exitPosition = _newPosition(forNode.rightParenthesis.offset); | 545 exitPosition = _newPosition(forNode.rightParenthesis.offset); |
| 545 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); | 546 sb = new SourceBuilder(file, forNode.rightParenthesis.offset); |
| 546 } | 547 } |
| 547 } | 548 } |
| 548 } | 549 } |
| 549 if (!_statementHasValidBody(forNode.forKeyword, forNode.body)) { | 550 if (!_statementHasValidBody(forNode.forKeyword, forNode.body)) { |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 915 LinkedEditGroup group = linkedPositionGroups[groupId]; | 916 LinkedEditGroup group = linkedPositionGroups[groupId]; |
| 916 if (group == null) { | 917 if (group == null) { |
| 917 group = new LinkedEditGroup.empty(); | 918 group = new LinkedEditGroup.empty(); |
| 918 linkedPositionGroups[groupId] = group; | 919 linkedPositionGroups[groupId] = group; |
| 919 } | 920 } |
| 920 return group; | 921 return group; |
| 921 } | 922 } |
| 922 | 923 |
| 923 void _insertBuilder(SourceBuilder builder, [int length = 0]) { | 924 void _insertBuilder(SourceBuilder builder, [int length = 0]) { |
| 924 { | 925 { |
| 925 SourceRange range = rangeStartLength(builder.offset, length); | 926 SourceRange range = new SourceRange(builder.offset, length); |
| 926 String text = builder.toString(); | 927 String text = builder.toString(); |
| 927 _addReplaceEdit(range, text); | 928 _addReplaceEdit(range, text); |
| 928 } | 929 } |
| 929 // add linked positions | 930 // add linked positions |
| 930 builder.linkedPositionGroups.forEach((String id, LinkedEditGroup group) { | 931 builder.linkedPositionGroups.forEach((String id, LinkedEditGroup group) { |
| 931 LinkedEditGroup fixGroup = _getLinkedPosition(id); | 932 LinkedEditGroup fixGroup = _getLinkedPosition(id); |
| 932 group.positions.forEach((Position position) { | 933 group.positions.forEach((Position position) { |
| 933 fixGroup.addPosition(position, group.length); | 934 fixGroup.addPosition(position, group.length); |
| 934 }); | 935 }); |
| 935 group.suggestions.forEach((LinkedEditSuggestion suggestion) { | 936 group.suggestions.forEach((LinkedEditSuggestion suggestion) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 final Token keyword; | 1025 final Token keyword; |
| 1025 final Token leftParenthesis, rightParenthesis; | 1026 final Token leftParenthesis, rightParenthesis; |
| 1026 final Expression condition; | 1027 final Expression condition; |
| 1027 final Statement block; | 1028 final Statement block; |
| 1028 | 1029 |
| 1029 _KeywordConditionBlockStructure(this.keyword, this.leftParenthesis, | 1030 _KeywordConditionBlockStructure(this.keyword, this.leftParenthesis, |
| 1030 this.condition, this.rightParenthesis, this.block); | 1031 this.condition, this.rightParenthesis, this.block); |
| 1031 | 1032 |
| 1032 int get offset => keyword.offset; | 1033 int get offset => keyword.offset; |
| 1033 } | 1034 } |
| OLD | NEW |