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

Side by Side Diff: pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart

Issue 2826283002: Complete for-each and switch statements (Closed)
Patch Set: Complete for-each and switch statements' Created 3 years, 8 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/analysis_server/test/services/completion/statement/statement_completion_test.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) 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/plugin/protocol/protocol.dart'; 9 import 'package:analysis_server/plugin/protocol/protocol.dart';
10 import 'package:analysis_server/src/protocol_server.dart' hide Element; 10 import 'package:analysis_server/src/protocol_server.dart' hide Element;
(...skipping 21 matching lines...) Expand all
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(
35 'SIMPLE_SEMICOLON', "Add a semicolon and newline"); 35 'SIMPLE_SEMICOLON', "Add a semicolon and newline");
36 static const COMPLETE_DO_STMT = const StatementCompletionKind( 36 static const COMPLETE_DO_STMT = const StatementCompletionKind(
37 'COMPLETE_DO_STMT', "Complete do-statement"); 37 'COMPLETE_DO_STMT', "Complete do-statement");
38 static const COMPLETE_IF_STMT = const StatementCompletionKind( 38 static const COMPLETE_IF_STMT = const StatementCompletionKind(
39 'COMPLETE_IF_STMT', "Complete if-statement"); 39 'COMPLETE_IF_STMT', "Complete if-statement");
40 static const COMPLETE_FOR_STMT = const StatementCompletionKind( 40 static const COMPLETE_FOR_STMT = const StatementCompletionKind(
41 'COMPLETE_FOR_STMT', "Complete for-statement"); 41 'COMPLETE_FOR_STMT', "Complete for-statement");
42 static const COMPLETE_FOR_EACH_STMT = const StatementCompletionKind(
43 'COMPLETE_FOR_EACH_STMT', "Complete for-each-statement");
44 static const COMPLETE_SWITCH_STMT = const StatementCompletionKind(
45 'COMPLETE_SWITCH_STMT', "Complete switch-statement");
42 static const COMPLETE_WHILE_STMT = const StatementCompletionKind( 46 static const COMPLETE_WHILE_STMT = const StatementCompletionKind(
43 'COMPLETE_WHILE_STMT', "Complete while-statement"); 47 'COMPLETE_WHILE_STMT', "Complete while-statement");
44 } 48 }
45 49
46 /** 50 /**
47 * A description of a statement completion. 51 * A description of a statement completion.
48 * 52 *
49 * Clients may not extend, implement or mix-in this class. 53 * Clients may not extend, implement or mix-in this class.
50 */ 54 */
51 class StatementCompletion { 55 class StatementCompletion {
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 } 231 }
228 232
229 String _baseNodeText(AstNode astNode) { 233 String _baseNodeText(AstNode astNode) {
230 String text = utils.getNodeText(astNode); 234 String text = utils.getNodeText(astNode);
231 if (text.endsWith(eol)) { 235 if (text.endsWith(eol)) {
232 text = text.substring(0, text.length - eol.length); 236 text = text.substring(0, text.length - eol.length);
233 } 237 }
234 return text; 238 return text;
235 } 239 }
236 240
241 bool _complete_controlFlowBlock() {
242 //TODO(messick) Implement _complete_controlFlowBlock
243 // Use statement completion to move the cursor to a new line outside the
244 // current block. The statement has no errors in this case. Used to jump
245 // out of do/for/if/while blocks.
246 //TODO(messick) Move has-errors checking into dispatch method.
247 return false;
248 }
249
237 bool _complete_doStatement() { 250 bool _complete_doStatement() {
238 if (errors.isEmpty || node is! DoStatement) { 251 if (errors.isEmpty || node is! DoStatement) {
239 return false; 252 return false;
240 } 253 }
241 DoStatement statement = node; 254 DoStatement statement = node;
242 SourceBuilder sb = _sourceBuilderAfterKeyword(statement.doKeyword); 255 SourceBuilder sb = _sourceBuilderAfterKeyword(statement.doKeyword);
243 bool hasWhileKeyword = statement.whileKeyword.lexeme == "while"; 256 bool hasWhileKeyword = statement.whileKeyword.lexeme == "while";
244 int exitDelta = 0; 257 int exitDelta = 0;
245 if (statement.body is EmptyStatement) { 258 if (statement.body is EmptyStatement) {
246 String text = utils.getNodeText(statement.body); 259 String text = utils.getNodeText(statement.body);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 _insertBuilder(sb); 317 _insertBuilder(sb);
305 if (exitDelta != 0) { 318 if (exitDelta != 0) {
306 exitPosition = 319 exitPosition =
307 new Position(exitPosition.file, exitPosition.offset + exitDelta); 320 new Position(exitPosition.file, exitPosition.offset + exitDelta);
308 } 321 }
309 _setCompletion(DartStatementCompletion.COMPLETE_DO_STMT); 322 _setCompletion(DartStatementCompletion.COMPLETE_DO_STMT);
310 return true; 323 return true;
311 } 324 }
312 325
313 bool _complete_forEachStatement() { 326 bool _complete_forEachStatement() {
314 // TODO(messick) Implement _complete_forEachStatement 327 if (errors.isEmpty || node is! ForEachStatement) {
315 return false; 328 return false;
329 }
330 ForEachStatement forNode = node;
331 if (forNode.inKeyword.isSynthetic) {
332 return false; // Can't happen -- would be parsed as a for-statement.
333 }
334 SourceBuilder sb =
335 new SourceBuilder(file, forNode.rightParenthesis.offset + 1);
336 AstNode name = forNode.identifier;
337 name ??= forNode.loopVariable;
338 String src = utils.getNodeText(forNode);
339 if (name == null) {
340 exitPosition = new Position(file, forNode.leftParenthesis.offset + 1);
341 src = src.substring(forNode.leftParenthesis.offset - forNode.offset);
342 if (src.startsWith(new RegExp(r'\(\s*in\s*\)'))) {
343 _addReplaceEdit(
344 rangeStartEnd(forNode.leftParenthesis.offset + 1,
345 forNode.rightParenthesis.offset),
346 ' in ');
347 } else if (src.startsWith(new RegExp(r'\(\s*in'))) {
348 _addReplaceEdit(
349 rangeStartEnd(
350 forNode.leftParenthesis.offset + 1, forNode.inKeyword.offset),
351 ' ');
352 }
353 } else if (_isSyntheticExpression(forNode.iterable)) {
354 exitPosition = new Position(file, forNode.rightParenthesis.offset + 1);
355 src = src.substring(forNode.inKeyword.offset - forNode.offset);
356 if (src.startsWith(new RegExp(r'in\s*\)'))) {
357 _addReplaceEdit(
358 rangeStartEnd(forNode.inKeyword.offset + forNode.inKeyword.length,
359 forNode.rightParenthesis.offset),
360 ' ');
361 }
362 }
363 if (_isEmptyStatement(forNode.body)) {
364 sb.append(' ');
365 _appendEmptyBraces(sb, exitPosition == null);
366 }
367 _insertBuilder(sb);
368 _setCompletion(DartStatementCompletion.COMPLETE_FOR_EACH_STMT);
369 return true;
316 } 370 }
317 371
318 bool _complete_forStatement() { 372 bool _complete_forStatement() {
319 if (errors.isEmpty || node is! ForStatement) { 373 if (errors.isEmpty || node is! ForStatement) {
320 return false; 374 return false;
321 } 375 }
322 ForStatement forNode = node; 376 ForStatement forNode = node;
323 SourceBuilder sb; 377 SourceBuilder sb;
324 int delta = 0; 378 int delta = 0;
325 if (forNode.leftParenthesis.isSynthetic) { 379 if (forNode.leftParenthesis.isSynthetic) {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 int insertOffset = error.offset + error.length; 530 int insertOffset = error.offset + error.length;
477 _addInsertEdit(insertOffset, ';'); 531 _addInsertEdit(insertOffset, ';');
478 int offset = _appendNewlinePlusIndent() + 1 /* ';' */; 532 int offset = _appendNewlinePlusIndent() + 1 /* ';' */;
479 _setCompletionAt(DartStatementCompletion.SIMPLE_SEMICOLON, offset); 533 _setCompletionAt(DartStatementCompletion.SIMPLE_SEMICOLON, offset);
480 return true; 534 return true;
481 } 535 }
482 return false; 536 return false;
483 } 537 }
484 538
485 bool _complete_switchStatement() { 539 bool _complete_switchStatement() {
486 // TODO(messick) Implement _complete_switchStatement 540 if (errors.isEmpty || node is! SwitchStatement) {
487 return false; 541 return false;
542 }
543 SourceBuilder sb;
544 SwitchStatement switchNode = node;
545 if (switchNode.leftParenthesis.isSynthetic &&
546 switchNode.rightParenthesis.isSynthetic) {
547 exitPosition = new Position(file, switchNode.switchKeyword.end + 2);
548 String src = utils.getNodeText(switchNode);
549 if (src
550 .substring(switchNode.switchKeyword.end - switchNode.offset)
551 .startsWith(new RegExp(r'[ \t]+'))) {
552 sb = new SourceBuilder(file, switchNode.switchKeyword.end + 1);
553 } else {
554 sb = new SourceBuilder(file, switchNode.switchKeyword.end);
555 sb.append(' ');
556 }
557 sb.append('()');
558 } else if (switchNode.leftParenthesis.isSynthetic ||
559 switchNode.rightParenthesis.isSynthetic) {
560 return false;
561 } else {
562 sb = new SourceBuilder(file, switchNode.rightParenthesis.offset + 1);
563 if (_isSyntheticExpression(switchNode.expression)) {
564 exitPosition =
565 new Position(file, switchNode.leftParenthesis.offset + 1);
566 }
567 }
568 if (switchNode
569 .leftBracket.isSynthetic /*&& switchNode.rightBracket.isSynthetic*/) {
570 // See https://github.com/dart-lang/sdk/issues/29391
571 sb.append(' ');
572 _appendEmptyBraces(sb, exitPosition == null);
573 }
574 _insertBuilder(sb);
575 _setCompletion(DartStatementCompletion.COMPLETE_SWITCH_STMT);
576 return true;
488 } 577 }
489 578
490 bool _complete_tryStatement() { 579 bool _complete_tryStatement() {
491 // TODO(messick) Implement _complete_tryStatement 580 // TODO(messick) Implement _complete_tryStatement
492 return false; 581 return false;
493 } 582 }
494 583
495 bool _complete_whileStatement() { 584 bool _complete_whileStatement() {
496 if (errors.isEmpty || node is! WhileStatement) { 585 if (errors.isEmpty || node is! WhileStatement) {
497 return false; 586 return false;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 if (exitOffset != null) { 642 if (exitOffset != null) {
554 exitPosition = _newPosition(exitOffset); 643 exitPosition = _newPosition(exitOffset);
555 } 644 }
556 } 645 }
557 } 646 }
558 647
559 bool _isEmptyBlock(AstNode stmt) { 648 bool _isEmptyBlock(AstNode stmt) {
560 return stmt is Block && stmt.statements.isEmpty; 649 return stmt is Block && stmt.statements.isEmpty;
561 } 650 }
562 651
652 bool _isEmptyStatement(AstNode stmt) {
653 return stmt is EmptyStatement || _isEmptyBlock(stmt);
654 }
655
563 bool _isSyntheticExpression(Expression expr) { 656 bool _isSyntheticExpression(Expression expr) {
564 return expr is SimpleIdentifier && expr.isSynthetic; 657 return expr is SimpleIdentifier && expr.isSynthetic;
565 } 658 }
566 659
567 bool _isEmptyStatement(AstNode stmt) {
568 return stmt is EmptyStatement || _isEmptyBlock(stmt);
569 }
570
571 Position _newPosition(int offset) { 660 Position _newPosition(int offset) {
572 return new Position(file, offset); 661 return new Position(file, offset);
573 } 662 }
574 663
575 void _setCompletion(StatementCompletionKind kind, [List args]) { 664 void _setCompletion(StatementCompletionKind kind, [List args]) {
576 assert(exitPosition != null); 665 assert(exitPosition != null);
577 change.selection = exitPosition; 666 change.selection = exitPosition;
578 change.message = formatList(kind.message, args); 667 change.message = formatList(kind.message, args);
579 linkedPositionGroups.values 668 linkedPositionGroups.values
580 .forEach((group) => change.addLinkedEditGroup(group)); 669 .forEach((group) => change.addLinkedEditGroup(group));
(...skipping 26 matching lines...) Expand all
607 final Token keyword; 696 final Token keyword;
608 final Token leftParenthesis, rightParenthesis; 697 final Token leftParenthesis, rightParenthesis;
609 final Expression condition; 698 final Expression condition;
610 final Statement block; 699 final Statement block;
611 700
612 _KeywordConditionBlockStructure(this.keyword, this.leftParenthesis, 701 _KeywordConditionBlockStructure(this.keyword, this.leftParenthesis,
613 this.condition, this.rightParenthesis, this.block); 702 this.condition, this.rightParenthesis, this.block);
614 703
615 int get offset => keyword.offset; 704 int get offset => keyword.offset;
616 } 705 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698