blob: a94f87b6f87a181003d65ea1565a8d9f7864f1a7 [file] [log] [blame]
// 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:analysis_server/src/protocol_server.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:nnbd_migration/nnbd_migration.dart';
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/expression_checks.dart';
import 'package:nnbd_migration/src/graph_builder.dart';
import 'package:nnbd_migration/src/node_builder.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
import 'package:nnbd_migration/src/potential_modification.dart';
import 'package:nnbd_migration/src/variables.dart';
/// Implementation of the [NullabilityMigration] public API.
class NullabilityMigrationImpl implements NullabilityMigration {
final NullabilityMigrationListener listener;
final _variables = Variables();
final _graph = NullabilityGraph();
final bool _permissive;
/// Prepares to perform nullability migration.
///
/// If [permissive] is `true`, exception handling logic will try to proceed
/// as far as possible even though the migration algorithm is not yet
/// complete. TODO(paulberry): remove this mode once the migration algorithm
/// is fully implemented.
NullabilityMigrationImpl(this.listener, {bool permissive: false})
: _permissive = permissive;
void finish() {
_graph.propagate();
for (var entry in _variables.getPotentialModifications().entries) {
var source = entry.key;
for (var potentialModification in entry.value) {
var fix = _SingleNullabilityFix(source, potentialModification);
listener.addFix(fix);
for (var edit in potentialModification.modifications) {
listener.addEdit(fix, edit);
}
}
}
}
void prepareInput(ResolvedUnitResult result) {
var unit = result.unit;
unit.accept(NodeBuilder(_variables, unit.declaredElement.source,
_permissive ? listener : null, _graph, result.typeProvider));
}
void processInput(ResolvedUnitResult result) {
var unit = result.unit;
unit.accept(GraphBuilder(result.typeProvider, _variables, _graph,
unit.declaredElement.source, _permissive ? listener : null));
}
}
/// Implementation of [SingleNullabilityFix] used internally by
/// [NullabilityMigration].
class _SingleNullabilityFix extends SingleNullabilityFix {
@override
final Source source;
@override
final NullabilityFixKind kind;
factory _SingleNullabilityFix(
Source source, PotentialModification potentialModification) {
// TODO(paulberry): once everything is migrated into the analysis server,
// the migration engine can just create SingleNullabilityFix objects
// directly and set their kind appropriately; we won't need to translate the
// kinds using a bunch of `is` checks.
NullabilityFixKind kind;
if (potentialModification is ExpressionChecks) {
kind = NullabilityFixKind.checkExpression;
} else if (potentialModification is DecoratedTypeAnnotation) {
kind = NullabilityFixKind.makeTypeNullable;
} else if (potentialModification is ConditionalModification) {
kind = potentialModification.discard.keepFalse
? NullabilityFixKind.discardThen
: NullabilityFixKind.discardElse;
} else if (potentialModification is PotentiallyAddImport) {
kind = NullabilityFixKind.addImport;
} else if (potentialModification is PotentiallyAddRequired) {
kind = NullabilityFixKind.addRequired;
} else {
throw new UnimplementedError('TODO(paulberry)');
}
return _SingleNullabilityFix._(source, kind);
}
_SingleNullabilityFix._(this.source, this.kind);
/// TODO(paulberry): do something better
Location get location => null;
}