| Index: pkg/analysis_server/lib/src/services/correction/assist_internal.dart
|
| diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
|
| index 525a198d0775746ccd58a30bee4c5079c91d9c15..cb69ae74d460a4c50cbc1aec91a4482b997d8e1f 100644
|
| --- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
|
| +++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
|
| @@ -84,6 +84,7 @@ class AssistProcessor {
|
| _addProposal_convertToIsNot_onIs();
|
| _addProposal_convertToIsNot_onNot();
|
| _addProposal_convertToIsNotEmpty();
|
| + _addProposal_createFieldFieldsConstructor();
|
| _addProposal_exchangeOperands();
|
| _addProposal_importAddShow();
|
| _addProposal_introduceLocalTestedType();
|
| @@ -215,6 +216,44 @@ class AssistProcessor {
|
| _addAssist(AssistKind.ADD_TYPE_ANNOTATION, []);
|
| }
|
|
|
| + void _addProposal_addTypeAnnotation_SimpleFormalParameter() {
|
| + AstNode node = this.node;
|
| + // should be the name of a simple parameter
|
| + if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
|
| + _coverageMarker();
|
| + return;
|
| + }
|
| + SimpleIdentifier name = node;
|
| + SimpleFormalParameter parameter = node.parent;
|
| + // the parameter should not have a type
|
| + if (parameter.type != null) {
|
| + _coverageMarker();
|
| + return;
|
| + }
|
| + // prepare propagated type
|
| + DartType type = name.propagatedType;
|
| + // TODO(scheglov) If the parameter is in a method declaration, and if the
|
| + // method overrides a method that has a type for the corresponding
|
| + // parameter, it would be nice to copy down the type from the overridden
|
| + // method.
|
| + if (type is! InterfaceType) {
|
| + _coverageMarker();
|
| + return;
|
| + }
|
| + // prepare type source
|
| + String typeSource;
|
| + {
|
| + _configureTargetLocation(node);
|
| + Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
|
| + typeSource = utils.getTypeSource(type, librariesToImport);
|
| + addLibraryImports(change, unitLibraryElement, librariesToImport);
|
| + }
|
| + // add edit
|
| + _addInsertEdit(name.offset, '$typeSource ');
|
| + // add proposal
|
| + _addAssist(AssistKind.ADD_TYPE_ANNOTATION, []);
|
| + }
|
| +
|
| void _addProposal_addTypeAnnotation_VariableDeclaration() {
|
| AstNode node = this.node;
|
| // check if "var v = 42;^"
|
| @@ -270,44 +309,6 @@ class AssistProcessor {
|
| _addAssist(AssistKind.ADD_TYPE_ANNOTATION, []);
|
| }
|
|
|
| - void _addProposal_addTypeAnnotation_SimpleFormalParameter() {
|
| - AstNode node = this.node;
|
| - // should be the name of a simple parameter
|
| - if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - SimpleIdentifier name = node;
|
| - SimpleFormalParameter parameter = node.parent;
|
| - // the parameter should not have a type
|
| - if (parameter.type != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare propagated type
|
| - DartType type = name.propagatedType;
|
| - // TODO(scheglov) If the parameter is in a method declaration, and if the
|
| - // method overrides a method that has a type for the corresponding
|
| - // parameter, it would be nice to copy down the type from the overridden
|
| - // method.
|
| - if (type is! InterfaceType) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare type source
|
| - String typeSource;
|
| - {
|
| - _configureTargetLocation(node);
|
| - Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
|
| - typeSource = utils.getTypeSource(type, librariesToImport);
|
| - addLibraryImports(change, unitLibraryElement, librariesToImport);
|
| - }
|
| - // add edit
|
| - _addInsertEdit(name.offset, '$typeSource ');
|
| - // add proposal
|
| - _addAssist(AssistKind.ADD_TYPE_ANNOTATION, []);
|
| - }
|
| -
|
| void _addProposal_assignToLocalVariable() {
|
| // prepare enclosing ExpressionStatement
|
| Statement statement = node.getAncestor((node) => node is Statement);
|
| @@ -578,6 +579,55 @@ class AssistProcessor {
|
| _addAssist(AssistKind.CONVERT_INTO_IS_NOT_EMPTY, []);
|
| }
|
|
|
| + void _addProposal_createFieldFieldsConstructor() {
|
| + // prepare enclosing ClassDeclaration
|
| + if (node is! ClassDeclaration) {
|
| + _coverageMarker();
|
| + return;
|
| + }
|
| + ClassDeclaration classDeclaration = node;
|
| + // prepare names of final fields covered be the selection
|
| + List<String> fieldNames = <String>[];
|
| + for (ClassMember member in classDeclaration.members) {
|
| + if (member is FieldDeclaration) {
|
| + if (member.end < selectionOffset) {
|
| + _coverageMarker();
|
| + continue;
|
| + }
|
| + if (member.offset > selectionOffset + selectionLength) {
|
| + _coverageMarker();
|
| + continue;
|
| + }
|
| + VariableDeclarationList variableList = member.fields;
|
| + if (variableList.isFinal) {
|
| + List<VariableDeclaration> variables = variableList.variables;
|
| + fieldNames.addAll(variables.map((v) => v.name.name));
|
| + }
|
| + }
|
| + }
|
| + // add proposal
|
| + if (fieldNames.isNotEmpty) {
|
| + ConstructorLocation targetLocation =
|
| + utils.findNewConstructorLocation(classDeclaration);
|
| + // build method source
|
| + SourceBuilder sb = new SourceBuilder(file, targetLocation.offset);
|
| + {
|
| + String indent = ' ';
|
| + sb.append(targetLocation.prefix);
|
| + sb.append(indent);
|
| + sb.append(classDeclaration.name.name);
|
| + sb.append('(');
|
| + sb.append(fieldNames.map((name) => 'this.$name').join(', '));
|
| + sb.append(');');
|
| + sb.append(targetLocation.suffix);
|
| + }
|
| + // insert source
|
| + _insertBuilder(sb);
|
| + // add proposal
|
| + _addAssist(AssistKind.CREATE_FINAL_FIELD_CONSTRUCTOR, []);
|
| + }
|
| + }
|
| +
|
| void _addProposal_exchangeOperands() {
|
| // check that user invokes quick assist on binary expression
|
| if (node is! BinaryExpression) {
|
|
|