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 |