@@ -127,6 +127,7 @@ class AssistProcessor {
127127 await _addProposal_addTypeAnnotation_SimpleFormalParameter ();
128128 await _addProposal_addTypeAnnotation_VariableDeclaration ();
129129 await _addProposal_assignToLocalVariable ();
130+ await _addProposal_convertClassToMixin ();
130131 await _addProposal_convertIntoFinalField ();
131132 await _addProposal_convertIntoGetter ();
132133 await _addProposal_convertDocumentationIntoBlock ();
@@ -431,6 +432,60 @@ class AssistProcessor {
431432 }
432433 }
433434
435+ Future <void > _addProposal_convertClassToMixin () async {
436+ ClassDeclaration classDeclaration =
437+ node.getAncestor ((n) => n is ClassDeclaration );
438+ if (classDeclaration == null ) {
439+ return ;
440+ }
441+ if (selectionOffset > classDeclaration.name.end ||
442+ selectionEnd < classDeclaration.classKeyword.offset) {
443+ return ;
444+ }
445+ if (classDeclaration.members
446+ .any ((member) => member is ConstructorDeclaration )) {
447+ return ;
448+ }
449+ _SuperclassReferenceFinder finder = new _SuperclassReferenceFinder ();
450+ classDeclaration.accept (finder);
451+ List <ClassElement > referencedClasses = finder.referencedClasses;
452+ List <InterfaceType > superclassConstraints = < InterfaceType > [];
453+ List <InterfaceType > interfaces = < InterfaceType > [];
454+
455+ ClassElement classElement = classDeclaration.declaredElement;
456+ for (InterfaceType type in classElement.mixins) {
457+ if (referencedClasses.contains (type.element)) {
458+ superclassConstraints.add (type);
459+ } else {
460+ interfaces.add (type);
461+ }
462+ }
463+ ExtendsClause extendsClause = classDeclaration.extendsClause;
464+ if (extendsClause != null ) {
465+ if (referencedClasses.length > superclassConstraints.length) {
466+ superclassConstraints.insert (0 , classElement.supertype);
467+ } else {
468+ interfaces.insert (0 , classElement.supertype);
469+ }
470+ }
471+ interfaces.addAll (classElement.interfaces);
472+
473+ DartChangeBuilder changeBuilder = new DartChangeBuilder (session);
474+ await changeBuilder.addFileEdit (file, (DartFileEditBuilder builder) {
475+ builder.addReplacement (
476+ range.startStart (
477+ classDeclaration.classKeyword, classDeclaration.leftBracket),
478+ (DartEditBuilder builder) {
479+ builder.write ('mixin ' );
480+ builder.write (classDeclaration.name.name);
481+ builder.writeTypes (superclassConstraints, prefix: ' on ' );
482+ builder.writeTypes (interfaces, prefix: ' implements ' );
483+ builder.write (' ' );
484+ });
485+ });
486+ _addAssistFromBuilder (changeBuilder, DartAssistKind .CONVERT_CLASS_TO_MIXIN );
487+ }
488+
434489 Future <void > _addProposal_convertDocumentationIntoBlock () async {
435490 // TODO(brianwilkerson) Determine whether this await is necessary.
436491 await null ;
@@ -3386,3 +3441,43 @@ class _SimpleIdentifierRecursiveAstVisitor extends RecursiveAstVisitor {
33863441 visitor (node);
33873442 }
33883443}
3444+
3445+ /**
3446+ * A visitor used to find all of the classes that define members referenced via
3447+ * `super` .
3448+ */
3449+ class _SuperclassReferenceFinder extends RecursiveAstVisitor {
3450+ final List <ClassElement > referencedClasses = < ClassElement > [];
3451+
3452+ _SuperclassReferenceFinder ();
3453+
3454+ @override
3455+ visitSuperExpression (SuperExpression node) {
3456+ AstNode parent = node.parent;
3457+ if (parent is BinaryExpression ) {
3458+ _addElement (parent.staticElement);
3459+ } else if (parent is IndexExpression ) {
3460+ _addElement (parent.staticElement);
3461+ } else if (parent is MethodInvocation ) {
3462+ _addIdentifier (parent.methodName);
3463+ } else if (parent is PrefixedIdentifier ) {
3464+ _addIdentifier (parent.identifier);
3465+ } else if (parent is PropertyAccess ) {
3466+ _addIdentifier (parent.propertyName);
3467+ }
3468+ return super .visitSuperExpression (node);
3469+ }
3470+
3471+ void _addElement (Element element) {
3472+ if (element is ExecutableElement ) {
3473+ Element enclosingElement = element.enclosingElement;
3474+ if (enclosingElement is ClassElement ) {
3475+ referencedClasses.add (enclosingElement);
3476+ }
3477+ }
3478+ }
3479+
3480+ void _addIdentifier (SimpleIdentifier identifier) {
3481+ _addElement (identifier.staticElement);
3482+ }
3483+ }
0 commit comments