// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:meta/meta.dart';
import 'package:nnbd_migration/fix_reason_target.dart';
import 'package:nnbd_migration/instrumentation.dart';
import 'package:nnbd_migration/nnbd_migration.dart';
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/edit_plan.dart';
import 'package:nnbd_migration/src/fix_builder.dart';
import 'package:nnbd_migration/src/utilities/hint_utils.dart';

/// Base class representing a change that might need to be made to an
/// expression.
abstract class ExpressionChange {
  /// The type of the expression after the change is applied.
  final DartType resultType;

  ExpressionChange(this.resultType);

  /// Description of the change.
  NullabilityFixDescription get description;

  /// Creates a [NodeProducingEditPlan] that applies the change to [innerPlan].
  NodeProducingEditPlan applyExpression(FixAggregator aggregator,
      NodeProducingEditPlan innerPlan, AtomicEditInfo? info);

  /// Creates a string that applies the change to the [inner] text string.
  String applyText(FixAggregator aggregator, String inner);

  /// Describes the change, for use in debugging.
  String describe();
}

/// Visitor that combines together the changes produced by [FixBuilder] into a
/// concrete set of source code edits using the infrastructure of [EditPlan].
class FixAggregator extends UnifyingAstVisitor<void> {
  /// Map from the [AstNode]s that need to have changes made, to the changes
  /// that need to be applied to them.
  final Map<AstNode?, NodeChange> _changes;

  /// The set of [EditPlan]s being accumulated.
  List<EditPlan> _plans = [];

  final EditPlanner planner;

  /// Map from library to the prefix we should use when inserting code that
  /// refers to it.
  final Map<LibraryElement?, String?> _importPrefixes = {};

  final bool _warnOnWeakCode;

  FixAggregator._(this.planner, this._changes, this._warnOnWeakCode,
      CompilationUnitElement compilationUnitElement) {
    for (var importElement in compilationUnitElement.library.libraryImports) {
      // TODO(paulberry): the `??=` should ensure that if there are two imports,
      // one prefixed and one not, we prefer the prefix.  Test this.
      _importPrefixes[importElement.importedLibrary] ??=
          importElement.prefix?.element.name;
    }
  }

  /// Creates the necessary Dart code to refer to the given element, using an
  /// import prefix if necessary.
  ///
  /// TODO(paulberry): if the element is not currently imported, we should
  /// update or add an import statement as necessary.
  String? elementToCode(Element element) {
    var name = element.name;
    var library = element.library;
    var prefix = _importPrefixes[library];
    if (prefix != null) {
      return '$prefix.$name';
    } else {
      return name;
    }
  }

  /// Gathers all the changes to nodes descended from [node] into a single
  /// [EditPlan].
  NodeProducingEditPlan innerPlanForNode(AstNode node) {
    var innerPlans = innerPlansForNode(node);
    return planner.passThrough(node, innerPlans: innerPlans);
  }

  /// Gathers all the changes to nodes descended from [node] into a list of
  /// [EditPlan]s, one for each change.
  List<EditPlan> innerPlansForNode(AstNode node) {
    var previousPlans = _plans;
    try {
      _plans = [];
      node.visitChildren(this);
      return _plans;
    } finally {
      _plans = previousPlans;
    }
  }

  /// Gathers all the changes to [node] and its descendants into a single
  /// [EditPlan].
  EditPlan planForNode(AstNode? node) {
    var change = _changes[node];
    if (change != null) {
      return change._apply(node!, this);
    } else {
      return planner.passThrough(node, innerPlans: innerPlansForNode(node!));
    }
  }

  /// Creates a string representation of the given type parameter element,
  /// suitable for inserting into the user's source code.
  String typeFormalToCode(TypeParameterElement formal) {
    var bound = formal.bound;
    if (bound == null ||
        bound is DynamicType ||
        (bound.isDartCoreObject &&
            bound.nullabilitySuffix != NullabilitySuffix.none)) {
      return formal.name;
    }
    return '${formal.name} extends ${typeToCode(bound)}';
  }

  String typeToCode(DartType type) {
    // TODO(paulberry): is it possible to share code with DartType.toString()
    // somehow?
    String suffix =
        type.nullabilitySuffix == NullabilitySuffix.question ? '?' : '';
    if (type is InterfaceType) {
      var name = elementToCode(type.element);
      var typeArguments = type.typeArguments;
      if (typeArguments.isEmpty) {
        return '$name$suffix';
      } else {
        var args = [for (var arg in typeArguments) typeToCode(arg)].join(', ');
        return '$name<$args>$suffix';
      }
    } else if (type is FunctionType) {
      var buffer = StringBuffer();
      buffer.write(typeToCode(type.returnType));
      buffer.write(' Function');
      var typeFormals = type.typeFormals;
      if (typeFormals.isNotEmpty) {
        var formals = [for (var formal in typeFormals) typeFormalToCode(formal)]
            .join(', ');
        buffer.write('<$formals>');
      }
      buffer.write('(');
      String optionalOrNamedCloser = '';
      bool commaNeeded = false;
      for (var parameter in type.parameters) {
        if (commaNeeded) {
          buffer.write(', ');
        } else {
          commaNeeded = true;
        }
        if (optionalOrNamedCloser.isEmpty && !parameter.isRequiredPositional) {
          if (parameter.isPositional) {
            buffer.write('[');
            optionalOrNamedCloser = ']';
          } else {
            buffer.write('{');
            optionalOrNamedCloser = '}';
          }
        }
        buffer.write(typeToCode(parameter.type));
        if (parameter.isNamed) {
          buffer.write(' ${parameter.name}');
        }
      }
      buffer.write(optionalOrNamedCloser);
      buffer.write(')');
      buffer.write(suffix);
      return buffer.toString();
    } else {
      return type.toString();
    }
  }

  @override
  void visitNode(AstNode node) {
    var change = _changes[node];
    if (change != null) {
      var innerPlan = change._apply(node, this);
      _plans.add(innerPlan);
    } else {
      node.visitChildren(this);
    }
  }

  /// Runs the [FixAggregator] on a [unit] and returns the resulting edits.
  static Map<int?, List<AtomicEdit>>? run(CompilationUnit unit,
      String? sourceText, Map<AstNode?, NodeChange> changes,
      {bool? removeViaComments = false, bool warnOnWeakCode = false}) {
    var planner = EditPlanner(unit.lineInfo, sourceText,
        removeViaComments: removeViaComments);
    var aggregator = FixAggregator._(
        planner, changes, warnOnWeakCode, unit.declaredElement!);
    unit.accept(aggregator);
    if (aggregator._plans.isEmpty) return {};
    EditPlan plan;
    if (aggregator._plans.length == 1) {
      plan = aggregator._plans[0];
    } else {
      plan = planner.passThrough(unit, innerPlans: aggregator._plans);
    }
    return planner.finalize(plan);
  }
}

/// [ExpressionChange] describing the addition of an `as` cast to an expression.
class IntroduceAsChange extends ExpressionChange {
  /// The type being cast to.
  final DartType type;

  /// Indicates whether this is a downcast.
  final bool isDowncast;

  IntroduceAsChange(this.type, {required this.isDowncast}) : super(type);

  @override
  NullabilityFixDescription get description => isDowncast
      ? NullabilityFixDescription.downcastExpression
      : NullabilityFixDescription.otherCastExpression;

  @override
  NodeProducingEditPlan applyExpression(FixAggregator aggregator,
          NodeProducingEditPlan innerPlan, AtomicEditInfo? info) =>
      aggregator.planner.addBinaryPostfix(
          innerPlan, TokenType.AS, aggregator.typeToCode(type),
          info: info);

  @override
  String applyText(FixAggregator aggregator, String inner) =>
      '$inner as ${aggregator.typeToCode(type)}';

  @override
  String describe() => 'IntroduceAsChange($type)';
}

/// [ExpressionChange] describing the addition of an `as` cast to an expression
/// having a Future type.
class IntroduceThenChange extends ExpressionChange {
  /// The change that should be made to the value the future completes with.
  final ExpressionChange innerChange;

  IntroduceThenChange(super.resultType, this.innerChange);

  @override
  NullabilityFixDescription get description =>
      NullabilityFixDescription.addThen;

  @override
  NodeProducingEditPlan applyExpression(FixAggregator aggregator,
          NodeProducingEditPlan innerPlan, AtomicEditInfo? info) =>
      aggregator.planner.addPostfix(innerPlan,
          '.then((value) => ${innerChange.applyText(aggregator, 'value')})',
          info: info);

  @override
  String applyText(FixAggregator aggregator, String inner) =>
      '$inner.then((value) => ${innerChange.applyText(aggregator, 'value')})';

  @override
  String describe() => 'IntroduceThenChange($innerChange)';
}

/// Reasons that a variable declaration is to be made late.
enum LateAdditionReason {
  /// It was inferred that the associated variable declaration is to be made
  /// late through the late-inferring algorithm.
  inference,

  /// It was inferred that the associated variable declaration is to be made
  /// late, because it is a test variable which is assigned during setup.
  testVariableInference,
}

/// Base class representing a kind of change that [FixAggregator] might make to
/// a particular AST node.
abstract class NodeChange<N extends AstNode> {
  NodeChange._();

  /// Indicates whether this node exists solely to provide informative
  /// information.
  bool get isInformative => false;

  Iterable<String> get _toStringParts => const [];

  @override
  String toString() => '$runtimeType(${_toStringParts.join(', ')})';

  /// Applies this change to the given [node], producing an [EditPlan].  The
  /// [aggregator] may be used to gather up any edits to the node's descendants
  /// into their own [EditPlan]s.
  ///
  /// Note: the reason the caller can't just gather up the edits and pass them
  /// in is that some changes don't preserve all of the structure of the nodes
  /// below them (e.g. dropping an unnecessary cast), so those changes need to
  /// be able to call the appropriate [aggregator] methods just on the nodes
  /// they need.
  ///
  /// May return `null` if no changes need to be made.
  EditPlan _apply(N node, FixAggregator aggregator);

  /// Creates the appropriate specialized kind of [NodeChange] appropriate for
  /// the given [node].
  static NodeChange<AstNode>? create(AstNode node) =>
      node.accept(_NodeChangeVisitor._instance);
}

/// Implementation of [NodeChange] specialized for operating on [Annotation]
/// nodes.
class NodeChangeForAnnotation extends NodeChange<Annotation> {
  /// Indicates whether the node should be changed into a `required` keyword.
  bool changeToRequiredKeyword = false;

  /// If [changeToRequiredKeyword] is `true`, the information that should be
  /// contained in the edit.
  AtomicEditInfo? changeToRequiredKeywordInfo;

  NodeChangeForAnnotation() : super._();

  @override
  Iterable<String> get _toStringParts =>
      [if (changeToRequiredKeyword) 'changeToRequiredKeyword'];

  @override
  EditPlan _apply(Annotation node, FixAggregator aggregator) {
    if (!changeToRequiredKeyword) {
      return aggregator.innerPlanForNode(node);
    }
    var name = node.name;
    if (name is PrefixedIdentifier) {
      name = name.identifier;
    }
    if (aggregator.planner.sourceText!.substring(name.offset, name.end) ==
        'required') {
      // The text `required` already exists in the annotation; we can just
      // extract it.
      return aggregator.planner.extract(
          node, aggregator.planForNode(name) as NodeProducingEditPlan,
          infoBefore: changeToRequiredKeywordInfo, alwaysDelete: true);
    } else {
      return aggregator.planner.replace(node,
          [AtomicEdit.insert('required', info: changeToRequiredKeywordInfo)]);
    }
  }
}

/// Implementation of [NodeChange] specialized for operating on [ArgumentList]
/// nodes.
class NodeChangeForArgumentList extends NodeChange<ArgumentList> {
  /// Map whose keys are the arguments that should be dropped from this argument
  /// list, if any.  Values are info about why the arguments are being dropped.
  final Map<Expression, AtomicEditInfo?> _argumentsToDrop = {};

  NodeChangeForArgumentList() : super._();

  /// Queries the map whose keys are the arguments that should be dropped from
  /// this argument list, if any.  Values are info about why the arguments are
  /// being dropped.
  @visibleForTesting
  Map<Expression, AtomicEditInfo?> get argumentsToDrop => _argumentsToDrop;

  @override
  Iterable<String> get _toStringParts =>
      [if (_argumentsToDrop.isNotEmpty) 'argumentsToDrop: $_argumentsToDrop'];

  /// Updates `this` so that the given [argument] will be dropped, using [info]
  /// to annotate the reason why it is being dropped.
  void dropArgument(Expression argument, AtomicEditInfo? info) {
    assert(!_argumentsToDrop.containsKey(argument));
    _argumentsToDrop[argument] = info;
  }

  @override
  EditPlan _apply(ArgumentList node, FixAggregator aggregator) {
    assert(_argumentsToDrop.keys.every((e) => identical(e.parent, node)));
    List<EditPlan> innerPlans = [];
    for (var argument in node.arguments) {
      if (_argumentsToDrop.containsKey(argument)) {
        innerPlans.add(aggregator.planner
            .removeNode(argument, info: _argumentsToDrop[argument]));
      } else {
        innerPlans.add(aggregator.planForNode(argument));
      }
    }
    return aggregator.planner.passThrough(node, innerPlans: innerPlans);
  }
}

/// Implementation of [NodeChange] specialized for operating on [AsExpression]
/// nodes.
class NodeChangeForAsExpression extends NodeChangeForExpression<AsExpression> {
  /// Indicates whether the cast should be removed.
  bool removeAs = false;

  @override
  Iterable<String> get _toStringParts =>
      [...super._toStringParts, if (removeAs) 'removeAs'];

  @override
  EditPlan _apply(AsExpression node, FixAggregator aggregator) {
    if (removeAs) {
      return aggregator.planner.extract(node,
          aggregator.planForNode(node.expression) as NodeProducingEditPlan,
          infoAfter:
              AtomicEditInfo(NullabilityFixDescription.removeAs, const {}));
    } else {
      return super._apply(node, aggregator);
    }
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [AssignmentExpression] nodes.
class NodeChangeForAssignment
    extends NodeChangeForExpression<AssignmentExpression>
    with NodeChangeForAssignmentLike {
  /// Indicates whether the user should be warned that the assignment is a
  /// null-aware assignment that will have no effect when strong checking is
  /// enabled.
  bool isWeakNullAware = false;

  @override
  Iterable<String> get _toStringParts =>
      [...super._toStringParts, if (isWeakNullAware) 'isWeakNullAware'];

  @override
  NodeProducingEditPlan _apply(
      AssignmentExpression node, FixAggregator aggregator) {
    var lhsPlan = aggregator.planForNode(node.leftHandSide);
    if (isWeakNullAware && !aggregator._warnOnWeakCode) {
      // Just keep the LHS
      return aggregator.planner.extract(node, lhsPlan as NodeProducingEditPlan,
          infoAfter: AtomicEditInfo(
              NullabilityFixDescription.removeNullAwareAssignment, const {}));
    }
    var operatorPlan = _makeOperatorPlan(aggregator, node, node.operator);
    var rhsPlan = aggregator.planForNode(node.rightHandSide);
    var innerPlans = <EditPlan>[
      lhsPlan,
      if (operatorPlan != null) operatorPlan,
      rhsPlan
    ];
    return _applyExpression(aggregator,
        aggregator.planner.passThrough(node, innerPlans: innerPlans));
  }

  EditPlan? _makeOperatorPlan(
      FixAggregator aggregator, AssignmentExpression node, Token operator) {
    var operatorPlan = super._makeOperatorPlan(aggregator, node, operator);
    if (operatorPlan != null) return operatorPlan;
    if (isWeakNullAware) {
      assert(aggregator._warnOnWeakCode);
      return aggregator.planner.informativeMessageForToken(node, operator,
          info: AtomicEditInfo(
              NullabilityFixDescription
                  .nullAwareAssignmentUnnecessaryInStrongMode,
              const {}));
    } else {
      return null;
    }
  }
}

/// Common behaviors for expressions that can represent an assignment (possibly
/// through desugaring).
mixin NodeChangeForAssignmentLike<N extends Expression>
    on NodeChangeForExpression<N> {
  /// Indicates whether the user should be warned that the assignment has a
  /// bad combined type (the return type of the combiner isn't assignable to the
  /// write type of the target).
  bool hasBadCombinedType = false;

  /// Indicates whether the user should be warned that the assignment has a
  /// nullable source type.
  bool hasNullableSource = false;

  @override
  Iterable<String> get _toStringParts => [
        ...super._toStringParts,
        if (hasBadCombinedType) 'hasBadCombinedType',
        if (hasNullableSource) 'hasNullableSource'
      ];

  EditPlan? _makeOperatorPlan(
      FixAggregator aggregator, N node, Token operator) {
    if (hasNullableSource) {
      return aggregator.planner.informativeMessageForToken(node, operator,
          info: AtomicEditInfo(
              NullabilityFixDescription.compoundAssignmentHasNullableSource,
              const {}));
    } else if (hasBadCombinedType) {
      return aggregator.planner.informativeMessageForToken(node, operator,
          info: AtomicEditInfo(
              NullabilityFixDescription.compoundAssignmentHasBadCombinedType,
              const {}));
    } else {
      return null;
    }
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [CompilationUnit] nodes.
class NodeChangeForCompilationUnit extends NodeChange<CompilationUnit> {
  /// A map of the imports that should be added, or the empty map if no imports
  /// should be added.
  ///
  /// Each import is expressed as a map entry whose key is the URI to import and
  /// whose value is the set of symbols to show.
  final Map<String, Set<String>> _addImports = {};

  bool removeLanguageVersionComment = false;

  NodeChangeForCompilationUnit() : super._();

  /// Queries a map of the imports that should be added, or the empty map if no
  /// imports should be added.
  ///
  /// Each import is expressed as a map entry whose key is the URI to import and
  /// whose value is the set of symbols to show.
  @visibleForTesting
  Map<String, Set<String>> get addImports => _addImports;

  @override
  Iterable<String> get _toStringParts => [
        if (_addImports.isNotEmpty) 'addImports: $_addImports',
        if (removeLanguageVersionComment) 'removeLanguageVersionComment'
      ];

  /// Updates `this` so that an import of [uri] will be added, showing [name].
  void addImport(String uri, String name) {
    (_addImports[uri] ??= {}).add(name);
  }

  @override
  EditPlan _apply(CompilationUnit node, FixAggregator aggregator) {
    List<EditPlan> innerPlans = [];
    if (removeLanguageVersionComment) {
      final comment = (node as CompilationUnitImpl).languageVersionToken!;
      innerPlans.add(aggregator.planner.replaceToken(node, comment, '',
          info: AtomicEditInfo(
              NullabilityFixDescription.removeLanguageVersionComment,
              const {})));
    }
    _processDirectives(node, aggregator, innerPlans);
    for (var declaration in node.declarations) {
      innerPlans.add(aggregator.planForNode(declaration));
    }
    return aggregator.planner.passThrough(node, innerPlans: innerPlans);
  }

  /// Adds the necessary inner plans to [innerPlans] for the directives part of
  /// [node].  This solely involves adding imports.
  void _processDirectives(CompilationUnit node, FixAggregator aggregator,
      List<EditPlan> innerPlans) {
    List<MapEntry<String, Set<String>>> importsToAdd =
        _addImports.entries.toList();
    importsToAdd.sort((x, y) => x.key.compareTo(y.key));

    void insertImport(int offset, MapEntry<String, Set<String>> importToAdd,
        {String prefix = '', String suffix = '\n'}) {
      var shownNames = importToAdd.value.toList();
      shownNames.sort();
      innerPlans.add(aggregator.planner.insertText(node, offset, [
        if (prefix.isNotEmpty) AtomicEdit.insert(prefix),
        AtomicEdit.insert(
            "import '${importToAdd.key}' show ${shownNames.join(', ')};",
            info: AtomicEditInfo(NullabilityFixDescription.addImport, {})),
        if (suffix.isNotEmpty) AtomicEdit.insert(suffix)
      ]));
    }

    if (node.directives.every((d) => d is LibraryDirective)) {
      while (importsToAdd.isNotEmpty) {
        insertImport(
            node.declarations.beginToken!.offset, importsToAdd.removeAt(0),
            suffix: importsToAdd.isEmpty ? '\n\n' : '\n');
      }
    } else {
      for (var directive in node.directives) {
        while (importsToAdd.isNotEmpty &&
            _shouldImportGoBefore(importsToAdd.first.key, directive)) {
          insertImport(directive.offset, importsToAdd.removeAt(0));
        }
        innerPlans.add(aggregator.planForNode(directive));
      }
      while (importsToAdd.isNotEmpty) {
        insertImport(node.directives.last.end, importsToAdd.removeAt(0),
            prefix: '\n', suffix: '');
      }
    }
  }

  /// Determines whether a new import of [newImportUri] should be sorted before
  /// an existing [directive].
  bool _shouldImportGoBefore(String newImportUri, Directive directive) {
    if (directive is ImportDirective) {
      return newImportUri.compareTo(directive.uri.stringValue!) < 0;
    } else if (directive is LibraryDirective) {
      // Library directives must come before imports.
      return false;
    } else {
      // Everything else tends to come after imports.
      return true;
    }
  }
}

/// Common infrastructure used by [NodeChange] objects that operate on AST nodes
/// with conditional behavior (if statements, if elements, and conditional
/// expressions).
mixin NodeChangeForConditional<N extends AstNode> on NodeChange<N> {
  /// If not `null`, indicates that the condition expression is known to
  /// evaluate to either `true` or `false`, so the other branch of the
  /// conditional is dead code and should be eliminated.
  bool? conditionValue;

  /// If [conditionValue] is not `null`, the reason that should be included in
  /// the [AtomicEditInfo] for the edit that removes the dead code.
  FixReasonInfo? conditionReason;

  @override
  Iterable<String> get _toStringParts =>
      [...super._toStringParts, if (conditionValue != null) 'conditionValue'];

  /// If dead code removal is warranted for [node], returns an [EditPlan] that
  /// removes the dead code (and performs appropriate updates within any
  /// descendant AST nodes that remain).  Otherwise returns `null`.
  EditPlan? _applyConditional(N node, FixAggregator aggregator,
      AstNode conditionNode, AstNode thenNode, AstNode? elseNode) {
    if (conditionValue == null) return null;
    if (aggregator._warnOnWeakCode) {
      var conditionPlan = aggregator.innerPlanForNode(conditionNode);
      var info = AtomicEditInfo(
          conditionValue!
              ? NullabilityFixDescription.conditionTrueInStrongMode
              : NullabilityFixDescription.conditionFalseInStrongMode,
          {FixReasonTarget.root: conditionReason});
      var commentedConditionPlan = aggregator.planner.addCommentPostfix(
          conditionPlan, '/* == $conditionValue */',
          info: info, isInformative: true);
      return aggregator.planner.passThrough(node, innerPlans: [
        commentedConditionPlan,
        aggregator.planForNode(thenNode),
        if (elseNode != null) aggregator.planForNode(elseNode)
      ]);
    }
    AstNode? nodeToKeep;
    NullabilityFixDescription descriptionBefore, descriptionAfter;
    if (conditionValue!) {
      nodeToKeep = thenNode;
      descriptionBefore = NullabilityFixDescription.discardCondition;
      if (elseNode == null) {
        descriptionAfter = descriptionBefore;
      } else {
        descriptionAfter = NullabilityFixDescription.discardElse;
      }
    } else {
      nodeToKeep = elseNode;
      descriptionBefore =
          descriptionAfter = NullabilityFixDescription.discardThen;
    }
    if (nodeToKeep == null ||
        nodeToKeep is Block && nodeToKeep.statements.isEmpty) {
      // The conditional node collapses to a no-op, so try to remove it
      // entirely.
      var info = AtomicEditInfo(NullabilityFixDescription.discardIf,
          {FixReasonTarget.root: conditionReason});
      var removeNode = aggregator.planner.tryRemoveNode(node, info: info);
      if (removeNode != null) {
        return removeNode;
      } else {
        // We can't remove the node because it's not inside a sequence, so we
        // have to create a suitable replacement.
        if (node is IfStatement) {
          return aggregator.planner
              .replace(node, [AtomicEdit.insert('{}', info: info)], info: info);
        } else if (node is IfElement) {
          return aggregator.planner.replace(
              node, [AtomicEdit.insert('...{}', info: info)],
              info: info);
        } else {
          // We should never get here; the only types of conditional nodes that
          // can wind up collapsing to a no-op are if statements and if
          // elements.
          throw StateError(
              'Unexpected node type collapses to no-op: ${node.runtimeType}');
        }
      }
    }
    var infoBefore = AtomicEditInfo(
        descriptionBefore, {FixReasonTarget.root: conditionReason});
    var infoAfter = AtomicEditInfo(
        descriptionAfter, {FixReasonTarget.root: conditionReason});
    if (nodeToKeep is Block && nodeToKeep.statements.length == 1) {
      var singleStatement = nodeToKeep.statements[0];
      if (singleStatement is VariableDeclarationStatement) {
        // It's not safe to eliminate the {} because it increases the scope of
        // the variable declarations
      } else {
        nodeToKeep = singleStatement;
      }
    }
    return aggregator.planner.extract(
        node, aggregator.planForNode(nodeToKeep) as NodeProducingEditPlan,
        infoBefore: infoBefore, infoAfter: infoAfter);
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [ConditionalExpression] nodes.
class NodeChangeForConditionalExpression
    extends NodeChangeForExpression<ConditionalExpression>
    with NodeChangeForConditional {
  @override
  EditPlan _apply(ConditionalExpression node, FixAggregator aggregator) {
    return _applyConditional(node, aggregator, node.condition,
            node.thenExpression, node.elseExpression) ??
        super._apply(node, aggregator);
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [DefaultFormalParameter] nodes.
class NodeChangeForDefaultFormalParameter
    extends NodeChange<DefaultFormalParameter> {
  /// Indicates whether a `required` keyword should be added to this node.
  bool addRequiredKeyword = false;

  /// If [addRequiredKeyword] is `true`, the information that should be
  /// contained in the edit.
  AtomicEditInfo? addRequiredKeywordInfo;

  /// If [addRequiredKeyword] is `true`, and there is a `/*required*/` hint,
  /// the hint comment that should be converted into a simple `required` string.
  HintComment? requiredHint;

  /// If non-null, indicates a `@required` annotation which should be removed
  /// from this node.
  Annotation? annotationToRemove;

  /// If [annotationToRemove] is non-null, the information that should be
  /// contained in the edit.
  AtomicEditInfo? removeAnnotationInfo;

  NodeChangeForDefaultFormalParameter() : super._();

  @override
  Iterable<String> get _toStringParts =>
      [if (addRequiredKeyword) 'addRequiredKeyword'];

  @override
  EditPlan _apply(DefaultFormalParameter node, FixAggregator aggregator) {
    if (!addRequiredKeyword) return aggregator.innerPlanForNode(node);

    if (requiredHint != null) {
      var innerPlan = aggregator.innerPlanForNode(node);
      return aggregator.planner.acceptPrefixHint(innerPlan, requiredHint!,
          info: addRequiredKeywordInfo);
    }

    var offset = node.firstTokenAfterCommentAndMetadata!.offset;
    return aggregator.planner.passThrough(node, innerPlans: [
      aggregator.planner.insertText(node, offset, [
        AtomicEdit.insert('required ', info: addRequiredKeywordInfo),
      ]),
      if (annotationToRemove != null)
        aggregator.planner
            .removeNode(annotationToRemove!, info: removeAnnotationInfo),
      ...aggregator.innerPlansForNode(node),
    ]);
  }
}

/// Implementation of [NodeChange] specialized for operating on [Expression]
/// nodes.
class NodeChangeForExpression<N extends Expression> extends NodeChange<N> {
  /// The list of [ExpressionChange] objects that should be applied to the
  /// expression, in the order they should be applied.
  final List<ExpressionChange> expressionChanges = [];

  /// The list of [AtomicEditInfo] objects corresponding to each change in
  /// [expressionChanges].
  final List<AtomicEditInfo?> expressionChangeInfos = [];

  NodeChangeForExpression() : super._();

  @override
  Iterable<String> get _toStringParts => [
        for (var expressionChange in expressionChanges)
          expressionChange.describe()
      ];

  void addExpressionChange(ExpressionChange change, AtomicEditInfo? info) {
    expressionChanges.add(change);
    expressionChangeInfos.add(info);
  }

  @override
  EditPlan _apply(N node, FixAggregator aggregator) {
    var innerPlan = aggregator.innerPlanForNode(node);
    return _applyExpression(aggregator, innerPlan);
  }

  /// If the expression needs to be wrapped in another expression (e.g. a null
  /// check), wraps the given [innerPlan] to produce appropriate result.
  /// Otherwise returns [innerPlan] unchanged.
  NodeProducingEditPlan _applyExpression(
      FixAggregator aggregator, NodeProducingEditPlan innerPlan) {
    var plan = innerPlan;
    for (int i = 0; i < expressionChanges.length; i++) {
      plan = expressionChanges[i]
          .applyExpression(aggregator, plan, expressionChangeInfos[i]);
    }
    return plan;
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [FieldFormalParameter] nodes.
class NodeChangeForFieldFormalParameter
    extends NodeChangeForType<FieldFormalParameter> {
  /// If not `null`, an explicit type annotation that should be added to the
  /// parameter.
  DartType? addExplicitType;

  NodeChangeForFieldFormalParameter() : super._();

  @override
  Iterable<String> get _toStringParts =>
      [if (addExplicitType != null) 'addExplicitType'];

  @override
  EditPlan _apply(FieldFormalParameter node, FixAggregator aggregator) {
    if (addExplicitType != null) {
      var typeText = aggregator.typeToCode(addExplicitType!);
      // Even a field formal parameter can use `var`, `final`.
      if (node.keyword?.keyword == Keyword.VAR) {
        // TODO(srawlins): Test instrumentation info.
        var info =
            AtomicEditInfo(NullabilityFixDescription.replaceVar(typeText), {});
        return aggregator.planner.passThrough(node, innerPlans: [
          aggregator.planner
              .replaceToken(node, node.keyword!, typeText, info: info),
          ...aggregator.innerPlansForNode(node),
        ]);
      } else {
        // TODO(srawlins): Test instrumentation info.
        var info =
            AtomicEditInfo(NullabilityFixDescription.addType(typeText), {});
        var offset = node.thisKeyword.offset;
        return aggregator.planner.passThrough(node, innerPlans: [
          aggregator.planner.insertText(node, offset, [
            AtomicEdit.insert(typeText, info: info),
            AtomicEdit.insert(' ')
          ]),
          ...aggregator.innerPlansForNode(node),
        ]);
      }
    } else {
      return super._apply(node, aggregator);
    }
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [FunctionTypedFormalParameter] nodes.
class NodeChangeForFunctionTypedFormalParameter
    extends NodeChangeForType<FunctionTypedFormalParameter> {
  NodeChangeForFunctionTypedFormalParameter() : super._();
}

/// Implementation of [NodeChange] specialized for operating on [IfElement]
/// nodes.
class NodeChangeForIfElement extends NodeChange<IfElement>
    with NodeChangeForConditional {
  NodeChangeForIfElement() : super._();

  @override
  EditPlan _apply(IfElement node, FixAggregator aggregator) {
    return _applyConditional(node, aggregator, node.expression,
            node.thenElement, node.elseElement) ??
        aggregator.innerPlanForNode(node);
  }
}

/// Implementation of [NodeChange] specialized for operating on [IfStatement]
/// nodes.
class NodeChangeForIfStatement extends NodeChange<IfStatement>
    with NodeChangeForConditional {
  NodeChangeForIfStatement() : super._();

  @override
  EditPlan _apply(IfStatement node, FixAggregator aggregator) {
    return _applyConditional(node, aggregator, node.expression,
            node.thenStatement, node.elseStatement) ??
        aggregator.innerPlanForNode(node);
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [MethodDeclaration] nodes.
class NodeChangeForMethodDeclaration extends NodeChange<MethodDeclaration> {
  /// If non-null, indicates a `@nullable` annotation which should be removed
  /// from this node.
  Annotation? annotationToRemove;

  /// If [annotationToRemove] is non-null, the information that should be
  /// contained in the edit.
  AtomicEditInfo? removeAnnotationInfo;

  NodeChangeForMethodDeclaration() : super._();

  @override
  Iterable<String> get _toStringParts =>
      [if (annotationToRemove != null) 'annotationToRemove'];

  @override
  EditPlan _apply(MethodDeclaration node, FixAggregator aggregator) {
    return aggregator.planner.passThrough(node, innerPlans: [
      if (annotationToRemove != null)
        aggregator.planner
            .removeNode(annotationToRemove!, info: removeAnnotationInfo),
      ...aggregator.innerPlansForNode(node),
    ]);
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [MethodInvocation] nodes.
class NodeChangeForMethodInvocation
    extends NodeChangeForExpression<MethodInvocation>
    with NodeChangeForNullAware {
  @override
  NodeProducingEditPlan _apply(
      MethodInvocation node, FixAggregator aggregator) {
    var target = node.target;
    var targetPlan = target == null ? null : aggregator.planForNode(target);
    var nullAwarePlan = _applyNullAware(node, aggregator);
    var methodNamePlan = aggregator.planForNode(node.methodName);
    var typeArguments = node.typeArguments;
    var typeArgumentsPlan =
        typeArguments == null ? null : aggregator.planForNode(typeArguments);
    var argumentListPlan = aggregator.planForNode(node.argumentList);
    var innerPlans = [
      if (targetPlan != null) targetPlan,
      if (nullAwarePlan != null) nullAwarePlan,
      methodNamePlan,
      if (typeArgumentsPlan != null) typeArgumentsPlan,
      argumentListPlan
    ];
    return _applyExpression(aggregator,
        aggregator.planner.passThrough(node, innerPlans: innerPlans));
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [SimpleIdentifier] nodes that represent a method name.
class NodeChangeForMethodName extends NodeChange<SimpleIdentifier> {
  /// The name the method name should be changed to, or `null` if no change
  /// should be made.
  String? _replacement;

  /// Info object associated with the replacement.
  AtomicEditInfo? _replacementInfo;

  NodeChangeForMethodName() : super._();

  /// Queries the name the method name should be changed to, or `null` if no
  /// change should be made.
  @visibleForTesting
  String? get replacement => _replacement;

  /// Queries the info object associated with the replacement.
  @visibleForTesting
  AtomicEditInfo? get replacementInfo => _replacementInfo;

  @override
  Iterable<String> get _toStringParts =>
      [if (replacement != null) 'replacement: $replacement'];

  /// Updates `this` so that the method name will be changed to [replacement],
  /// using [info] to annotate the reason for the change.
  void replaceWith(String replacement, AtomicEditInfo? info) {
    assert(_replacement == null);
    _replacement = replacement;
    _replacementInfo = info;
  }

  @override
  EditPlan _apply(SimpleIdentifier node, FixAggregator aggregator) {
    if (replacement != null) {
      return aggregator.planner.replace(
          node, [AtomicEdit.insert(replacement!, info: replacementInfo)],
          info: replacementInfo);
    } else {
      return aggregator.innerPlanForNode(node);
    }
  }
}

/// Common infrastructure used by [NodeChange] objects that operate on AST nodes
/// with that can be null-aware (method invocations and property accesses).
mixin NodeChangeForNullAware<N extends Expression> on NodeChange<N> {
  /// Indicates how null-awareness should be handled.
  NullAwarenessRemovalType nullAwarenessRemoval = NullAwarenessRemovalType.none;

  @override
  Iterable<String> get _toStringParts => [
        ...super._toStringParts,
        if (nullAwarenessRemoval == NullAwarenessRemovalType.strong)
          'removeNullAwareness (strong)'
        else if (nullAwarenessRemoval == NullAwarenessRemovalType.weak)
          'removeNullAwareness (weak)'
      ];

  /// Returns an [EditPlan] that removes null awareness, if appropriate.
  /// Otherwise returns `null`.
  EditPlan? _applyNullAware(N node, FixAggregator aggregator) {
    if (nullAwarenessRemoval == NullAwarenessRemovalType.none) return null;
    var weak = aggregator._warnOnWeakCode &&
        nullAwarenessRemoval == NullAwarenessRemovalType.weak;
    var description = weak
        ? NullabilityFixDescription.nullAwarenessUnnecessaryInStrongMode
        : NullabilityFixDescription.removeNullAwareness;
    return aggregator.planner.removeNullAwareness(node,
        info: AtomicEditInfo(description, const {}), isInformative: weak);
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [PostfixExpression] nodes.
class NodeChangeForPostfixExpression
    extends NodeChangeForExpression<PostfixExpression>
    with NodeChangeForAssignmentLike {
  @override
  NodeProducingEditPlan _apply(
      PostfixExpression node, FixAggregator aggregator) {
    var operandPlan = aggregator.planForNode(node.operand);
    var operatorPlan = _makeOperatorPlan(aggregator, node, node.operator);
    var innerPlans = <EditPlan>[
      operandPlan,
      if (operatorPlan != null) operatorPlan
    ];
    return _applyExpression(aggregator,
        aggregator.planner.passThrough(node, innerPlans: innerPlans));
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [PrefixExpression] nodes.
class NodeChangeForPrefixExpression
    extends NodeChangeForExpression<PrefixExpression>
    with NodeChangeForAssignmentLike {
  @override
  NodeProducingEditPlan _apply(
      PrefixExpression node, FixAggregator aggregator) {
    var operatorPlan = _makeOperatorPlan(aggregator, node, node.operator);
    var operandPlan = aggregator.planForNode(node.operand);
    var innerPlans = <EditPlan>[
      if (operatorPlan != null) operatorPlan,
      operandPlan
    ];
    return _applyExpression(aggregator,
        aggregator.planner.passThrough(node, innerPlans: innerPlans));
  }
}

/// Implementation of [NodeChange] specialized for operating on [PropertyAccess]
/// nodes.
class NodeChangeForPropertyAccess
    extends NodeChangeForExpression<PropertyAccess>
    with NodeChangeForNullAware {
  @override
  NodeProducingEditPlan _apply(PropertyAccess node, FixAggregator aggregator) {
    var targetPlan =
        node.target == null ? null : aggregator.planForNode(node.target);
    var nullAwarePlan = _applyNullAware(node, aggregator);
    var propertyNamePlan = aggregator.planForNode(node.propertyName);
    var innerPlans = [
      if (targetPlan != null) targetPlan,
      if (nullAwarePlan != null) nullAwarePlan,
      propertyNamePlan
    ];
    return _applyExpression(aggregator,
        aggregator.planner.passThrough(node, innerPlans: innerPlans));
  }
}

/// Implementation of [NodeChange] specialized for operating on [ShowCombinator]
/// nodes.
class NodeChangeForShowCombinator extends NodeChange<ShowCombinator> {
  /// A set of the names that should be added, or the empty set if no names
  /// should be added.
  final Set<String> _addNames = {};

  NodeChangeForShowCombinator() : super._();

  /// Queries the set of names that should be added, or the empty set if no
  /// names should be added.
  @visibleForTesting
  Iterable<String> get addNames => _addNames;

  @override
  Iterable<String> get _toStringParts => [
        if (_addNames.isNotEmpty) 'addNames: $_addNames',
      ];

  /// Updates `this` so that [name] will be added.
  void addName(String name) {
    _addNames.add(name);
  }

  @override
  EditPlan _apply(ShowCombinator node, FixAggregator aggregator) {
    List<EditPlan> innerPlans = [];
    List<String> namesToAdd = _addNames.toList();
    namesToAdd.sort();

    void insertName(int offset, String nameToAdd,
        {String prefix = '', String suffix = ', '}) {
      innerPlans.add(aggregator.planner.insertText(node, offset, [
        if (prefix.isNotEmpty) AtomicEdit.insert(prefix),
        AtomicEdit.insert(nameToAdd),
        if (suffix.isNotEmpty) AtomicEdit.insert(suffix)
      ]));
    }

    for (var shownName in node.shownNames) {
      while (namesToAdd.isNotEmpty &&
          namesToAdd.first.compareTo(shownName.name) < 0) {
        insertName(shownName.offset, namesToAdd.removeAt(0));
      }
      innerPlans.add(aggregator.planForNode(shownName));
    }
    while (namesToAdd.isNotEmpty) {
      insertName(node.shownNames.last.end, namesToAdd.removeAt(0),
          prefix: ', ', suffix: '');
    }
    return aggregator.planner.passThrough(node, innerPlans: innerPlans);
  }
}

/// Implementation of [NodeChange] specialized for operating on
/// [SimpleFormalParameter] nodes.
class NodeChangeForSimpleFormalParameter
    extends NodeChange<SimpleFormalParameter> {
  /// If not `null`, an explicit type annotation that should be added to the
  /// parameter.
  DartType? addExplicitType;

  NodeChangeForSimpleFormalParameter() : super._();

  @override
  Iterable<String> get _toStringParts =>
      [if (addExplicitType != null) 'addExplicitType'];

  @override
  EditPlan _apply(SimpleFormalParameter node, FixAggregator aggregator) {
    var innerPlan = aggregator.innerPlanForNode(node);
    if (addExplicitType == null) return innerPlan;
    var typeText = aggregator.typeToCode(addExplicitType!);
    if (node.keyword?.keyword == Keyword.VAR) {
      // TODO(srawlins): Test instrumentation info.
      var info =
          AtomicEditInfo(NullabilityFixDescription.replaceVar(typeText), {});
      return aggregator.planner.passThrough(node, innerPlans: [
        aggregator.planner
            .replaceToken(node, node.keyword!, typeText, info: info),
        ...aggregator.innerPlansForNode(node),
      ]);
    } else {
      // TODO(srawlins): Test instrumentation info.
      var info =
          AtomicEditInfo(NullabilityFixDescription.addType(typeText), {});
      // Skip past the offset of any metadata, a potential `final` keyword, and
      // a potential `covariant` keyword.
      var offset = node.type?.offset ?? node.name!.offset;
      return aggregator.planner.passThrough(node, innerPlans: [
        aggregator.planner.insertText(node, offset,
            [AtomicEdit.insert(typeText, info: info), AtomicEdit.insert(' ')]),
        ...aggregator.innerPlansForNode(node),
      ]);
    }
  }
}

/// Implementation of [NodeChange] specialized for operating on nodes which
/// represent a type, and can be made and hinted nullable and non-nullable.
abstract class NodeChangeForType<N extends AstNode> extends NodeChange<N> {
  bool _makeNullable = false;

  HintComment? _nullabilityHint;

  /// The decorated type of the type annotation, or `null` if there is no
  /// decorated type info of interest.  If [makeNullable] is `true`, the node
  /// from this type will be attached to the edit that adds the `?`. If
  /// [_makeNullable] is `false`, the node from this type will be attached to
  /// the information about why the node wasn't made nullable.
  DecoratedType? _decoratedType;

  NodeChangeForType._() : super._();

  @override
  bool get isInformative => !_makeNullable;

  /// Indicates whether the type should be made nullable by adding a `?`.
  bool get makeNullable => _makeNullable;

  /// If we are making the type nullable due to a hint, the comment that caused
  /// it.
  HintComment? get nullabilityHint => _nullabilityHint;

  @override
  Iterable<String> get _toStringParts => [
        if (_makeNullable) 'makeNullable',
        if (_nullabilityHint != null) 'nullabilityHint'
      ];

  void recordNullability(DecoratedType decoratedType, bool makeNullable,
      {HintComment? nullabilityHint}) {
    _decoratedType = decoratedType;
    _makeNullable = makeNullable;
    _nullabilityHint = nullabilityHint;
  }

  @override
  EditPlan _apply(N node, FixAggregator aggregator) {
    var innerPlan = aggregator.innerPlanForNode(node);
    if (_decoratedType == null) return innerPlan;
    var typeName =
        _decoratedType!.type!.getDisplayString(withNullability: false);
    var fixReasons = {FixReasonTarget.root: _decoratedType!.node};
    if (_makeNullable) {
      var hint = _nullabilityHint;
      if (hint != null) {
        return aggregator.planner.acceptSuffixHint(innerPlan, hint,
            info: AtomicEditInfo(
                NullabilityFixDescription.makeTypeNullableDueToHint(typeName),
                fixReasons,
                hintComment: hint));
      } else {
        return aggregator.planner.makeNullable(innerPlan,
            info: AtomicEditInfo(
                NullabilityFixDescription.makeTypeNullable(typeName),
                fixReasons));
      }
    } else {
      var hint = _nullabilityHint;
      if (hint != null) {
        return aggregator.planner.dropNullabilityHint(innerPlan, hint,
            info: AtomicEditInfo(
                NullabilityFixDescription.typeNotMadeNullableDueToHint(
                    typeName),
                fixReasons,
                hintComment: hint));
      } else {
        return aggregator.planner.explainNonNullable(innerPlan,
            info: AtomicEditInfo(
                NullabilityFixDescription.typeNotMadeNullable(typeName),
                fixReasons));
      }
    }
  }
}

/// Implementation of [NodeChange] specialized for operating on [TypeAnnotation]
/// nodes.
class NodeChangeForTypeAnnotation extends NodeChangeForType<TypeAnnotation> {
  NodeChangeForTypeAnnotation() : super._();
}

/// Implementation of [NodeChange] specialized for operating on
/// [VariableDeclarationList] nodes.
class NodeChangeForVariableDeclarationList
    extends NodeChange<VariableDeclarationList> {
  /// If an explicit type should be added to this variable declaration, the type
  /// that should be added.  Otherwise `null`.
  DartType? addExplicitType;

  /// Indicates whether a "late" annotation should be added to this variable
  /// declaration, caused by inference.
  LateAdditionReason? lateAdditionReason;

  /// If a "late" annotation should be added to this variable declaration, and
  /// the cause is a "late" hint, the hint that caused it.  Otherwise `null`.
  HintComment? lateHint;

  NodeChangeForVariableDeclarationList() : super._();

  @override
  Iterable<String> get _toStringParts => [
        if (addExplicitType != null) 'addExplicitType',
        if (lateAdditionReason != null) 'lateAdditionReason',
        if (lateHint != null) 'lateHint'
      ];

  @override
  EditPlan _apply(VariableDeclarationList node, FixAggregator aggregator) {
    List<EditPlan> innerPlans = [];
    if (lateAdditionReason != null) {
      var description = lateAdditionReason == LateAdditionReason.inference
          ? NullabilityFixDescription.addLate
          : NullabilityFixDescription.addLateDueToTestSetup;
      var info = AtomicEditInfo(description, {});
      innerPlans.add(aggregator.planner.insertText(
          node,
          node.firstTokenAfterCommentAndMetadata.offset,
          [AtomicEdit.insert('late', info: info), AtomicEdit.insert(' ')]));
    }
    if (addExplicitType != null) {
      var typeText = aggregator.typeToCode(addExplicitType!);
      if (node.keyword?.keyword == Keyword.VAR) {
        var info =
            AtomicEditInfo(NullabilityFixDescription.replaceVar(typeText), {});
        innerPlans.add(aggregator.planner
            .replaceToken(node, node.keyword!, typeText, info: info));
      } else {
        var info =
            AtomicEditInfo(NullabilityFixDescription.addType(typeText), {});
        innerPlans.add(aggregator.planner.insertText(
            node,
            node.variables.first.offset,
            [AtomicEdit.insert(typeText, info: info), AtomicEdit.insert(' ')]));
      }
    }
    innerPlans.addAll(aggregator.innerPlansForNode(node));
    var plan = aggregator.planner.passThrough(node, innerPlans: innerPlans);
    if (lateHint != null) {
      var description = lateHint!.kind == HintCommentKind.late_
          ? NullabilityFixDescription.addLateDueToHint
          : NullabilityFixDescription.addLateFinalDueToHint;
      plan = aggregator.planner.acceptPrefixHint(plan, lateHint!,
          info: AtomicEditInfo(description, {}, hintComment: lateHint));
    }
    return plan;
  }
}

/// [ExpressionChange] describing the addition of a comment explaining that a
/// literal `null` could not be migrated.
class NoValidMigrationChange extends ExpressionChange {
  NoValidMigrationChange(super.resultType);

  @override
  NullabilityFixDescription get description =>
      NullabilityFixDescription.noValidMigrationForNull;

  @override
  NodeProducingEditPlan applyExpression(FixAggregator aggregator,
          NodeProducingEditPlan innerPlan, AtomicEditInfo? info) =>
      aggregator.planner.addCommentPostfix(
          innerPlan, '/* no valid migration */',
          info: info, isInformative: true);

  @override
  String applyText(FixAggregator aggregator, String inner) =>
      '$inner /* no valid migration */';

  @override
  String describe() => 'NoValidMigrationChange';
}

/// Enum used by [NodeChangeForNullAware] to indicate how null awareness should
/// be handled.
enum NullAwarenessRemovalType {
  /// Do not remove null awareness.
  none,

  /// If warning on weak code, issue a warning; otherwise remove null awareness.
  weak,

  /// Remove null awareness unconditionally.
  strong,
}

/// [ExpressionChange] describing the addition of an `!` after an expression.
class NullCheckChange extends ExpressionChange {
  /// The hint that is causing this `!` to be added, if any.
  final HintComment? hint;

  NullCheckChange(super.resultType, {this.hint});

  @override
  NullabilityFixDescription get description =>
      NullabilityFixDescription.checkExpression;

  @override
  NodeProducingEditPlan applyExpression(FixAggregator aggregator,
      NodeProducingEditPlan innerPlan, AtomicEditInfo? info) {
    if (hint != null) {
      return aggregator.planner.acceptSuffixHint(innerPlan, hint!, info: info);
    } else {
      return aggregator.planner
          .addUnaryPostfix(innerPlan, TokenType.BANG, info: info);
    }
  }

  @override
  String applyText(FixAggregator aggregator, String inner) => '$inner!';

  @override
  String describe() => 'NullCheckChange';
}

/// Visitor that creates an appropriate [NodeChange] object for the node being
/// visited.
class _NodeChangeVisitor extends GeneralizingAstVisitor<NodeChange<AstNode>> {
  static final _instance = _NodeChangeVisitor();

  @override
  NodeChange visitAnnotation(Annotation node) => NodeChangeForAnnotation();

  @override
  NodeChange visitArgumentList(ArgumentList node) =>
      NodeChangeForArgumentList();

  @override
  NodeChange visitAsExpression(AsExpression node) =>
      NodeChangeForAsExpression();

  @override
  NodeChange visitAssignmentExpression(AssignmentExpression node) =>
      NodeChangeForAssignment();

  @override
  NodeChange visitCompilationUnit(CompilationUnit node) =>
      NodeChangeForCompilationUnit();

  @override
  NodeChange visitConditionalExpression(ConditionalExpression node) =>
      NodeChangeForConditionalExpression();

  @override
  NodeChange visitDefaultFormalParameter(DefaultFormalParameter node) =>
      NodeChangeForDefaultFormalParameter();

  @override
  NodeChange visitExpression(Expression node) => NodeChangeForExpression();

  @override
  NodeChange visitFieldFormalParameter(FieldFormalParameter node) =>
      NodeChangeForFieldFormalParameter();

  @override
  NodeChange visitFunctionTypedFormalParameter(
          FunctionTypedFormalParameter node) =>
      NodeChangeForFunctionTypedFormalParameter();

  @override
  NodeChange visitGenericFunctionType(GenericFunctionType node) =>
      NodeChangeForTypeAnnotation();

  @override
  NodeChange visitIfElement(IfElement node) => NodeChangeForIfElement();

  @override
  NodeChange visitIfStatement(IfStatement node) => NodeChangeForIfStatement();

  @override
  NodeChange visitMethodDeclaration(MethodDeclaration node) =>
      NodeChangeForMethodDeclaration();

  @override
  NodeChange visitMethodInvocation(MethodInvocation node) =>
      NodeChangeForMethodInvocation();

  @override
  NodeChange visitNamedType(NamedType node) => NodeChangeForTypeAnnotation();

  @override
  NodeChange visitNode(AstNode node) =>
      throw StateError('Unexpected node type: ${node.runtimeType}');

  @override
  NodeChange visitPostfixExpression(PostfixExpression node) =>
      NodeChangeForPostfixExpression();

  @override
  NodeChange visitPrefixExpression(PrefixExpression node) =>
      NodeChangeForPrefixExpression();

  @override
  NodeChange visitPropertyAccess(PropertyAccess node) =>
      NodeChangeForPropertyAccess();

  @override
  NodeChange visitShowCombinator(ShowCombinator node) =>
      NodeChangeForShowCombinator();

  @override
  NodeChange visitSimpleFormalParameter(SimpleFormalParameter node) =>
      NodeChangeForSimpleFormalParameter();

  @override
  NodeChange? visitSimpleIdentifier(SimpleIdentifier node) {
    var parent = node.parent;
    if (parent is MethodInvocation && identical(node, parent.methodName)) {
      return NodeChangeForMethodName();
    } else {
      return super.visitSimpleIdentifier(node);
    }
  }

  @override
  NodeChange visitVariableDeclarationList(VariableDeclarationList node) =>
      NodeChangeForVariableDeclarationList();
}
