| // 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; |
| } |