blob: 019900deb323be193b2052e0ec29c28c05d348ae [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/dart/ast/ast.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:meta/meta.dart';
import 'package:nnbd_migration/instrumentation.dart';
import 'package:nnbd_migration/src/nullability_migration_impl.dart';
/// Description of fixes that might be performed by nullability migration.
class NullabilityFixDescription {
/// An if-test or conditional expression needs to have its condition and
/// "then" branch discarded.
static const discardThen = const NullabilityFixDescription._(
appliedMessage: 'Discarded an unreachable conditional then branch',
kind: NullabilityFixKind.discardThen,
);
/// An if-test or conditional expression needs to have its condition
/// discarded.
static const discardCondition = const NullabilityFixDescription._(
appliedMessage: 'Discarded a condition which is always true',
kind: NullabilityFixKind.discardCondition,
);
/// An if-test or conditional expression needs to have its condition and
/// "else" branch discarded.
static const discardElse = const NullabilityFixDescription._(
appliedMessage: 'Discarded an unreachable conditional else branch',
kind: NullabilityFixKind.discardElse,
);
/// An expression's value needs to be null-checked.
static const checkExpression = const NullabilityFixDescription._(
appliedMessage: 'Added a non-null assertion to nullable expression',
kind: NullabilityFixKind.checkExpression,
);
/// A message used by dartfix to indicate a fix has been applied.
final String appliedMessage;
/// The kind of fix described.
final NullabilityFixKind kind;
/// A formal parameter needs to have a required keyword added.
factory NullabilityFixDescription.addRequired(
String className, String functionName, String paramName) =>
NullabilityFixDescription._(
appliedMessage: "Add 'required' keyword to parameter '$paramName' in " +
(className == null ? functionName : "'$className.$functionName'"),
kind: NullabilityFixKind.addRequired,
);
/// An explicit type mentioned in the source program needs to be made
/// nullable.
factory NullabilityFixDescription.makeTypeNullable(String type) =>
NullabilityFixDescription._(
appliedMessage: "Changed type '$type' to be nullable",
kind: NullabilityFixKind.makeTypeNullable,
);
const NullabilityFixDescription._(
{@required this.appliedMessage, @required this.kind});
}
/// An enumeration of the various kinds of nullability fixes.
enum NullabilityFixKind {
addRequired,
checkExpression,
discardCondition,
discardElse,
discardThen,
makeTypeNullable,
noModification,
}
/// Provisional API for DartFix to perform nullability migration.
///
/// Usage: pass each input source file to [prepareInput]. Then pass each input
/// source file to [processInput]. Then pass each input source file to
/// [finalizeInput]. Then call [finish] to obtain the modifications that need
/// to be made to each source file.
abstract class NullabilityMigration {
/// 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.
///
/// [useFixBuilder] indicates whether migration should use the new
/// [FixBuilder] infrastructure. Once FixBuilder is at feature parity with
/// the old implementation, this option will be removed and FixBuilder will
/// be used unconditionally.
factory NullabilityMigration(NullabilityMigrationListener listener,
{bool permissive,
NullabilityMigrationInstrumentation instrumentation,
bool useFixBuilder}) = NullabilityMigrationImpl;
void finalizeInput(ResolvedUnitResult result);
void finish();
void prepareInput(ResolvedUnitResult result);
void processInput(ResolvedUnitResult result);
}
/// [NullabilityMigrationListener] is used by [NullabilityMigration]
/// to communicate source changes or "fixes" to the client.
abstract class NullabilityMigrationListener {
/// [addEdit] is called once for each source edit, in the order in which they
/// appear in the source file.
void addEdit(SingleNullabilityFix fix, SourceEdit edit);
/// [addFix] is called once for each source change.
void addFix(SingleNullabilityFix fix);
/// [reportException] is called once for each exception that occurs in
/// "permissive mode", reporting the location of the exception and the
/// exception details.
void reportException(
Source source, AstNode node, Object exception, StackTrace stackTrace);
}
/// Representation of a single conceptual change made by the nullability
/// migration algorithm. This change might require multiple source edits to
/// achieve.
abstract class SingleNullabilityFix {
/// What kind of fix this is.
NullabilityFixDescription get description;
/// Locations of the change, for reporting to the user.
List<Location> get locations;
/// File to change.
Source get source;
}