Permissive mode reports the exceptions that were thrown and ignored
Change-Id: I1876577acc43ba076ff4eec3b2891e329c109c24
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105407
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart b/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
index 0525b77..d14c29a 100644
--- a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
@@ -132,6 +132,7 @@
listener.otherSuggestions,
hasErrors,
listener.sourceChange.edits,
+ details: listener.details,
).toResponse(request.id);
} finally {
server.contextManager.driverMap.values
@@ -143,6 +144,7 @@
listener.otherSuggestions,
hasErrors,
listener.sourceChange.edits,
+ details: listener.details,
).toResponse(request.id);
}
diff --git a/pkg/analysis_server/lib/src/edit/fix/dartfix_listener.dart b/pkg/analysis_server/lib/src/edit/fix/dartfix_listener.dart
index c1e9639..58657c0 100644
--- a/pkg/analysis_server/lib/src/edit/fix/dartfix_listener.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/dartfix_listener.dart
@@ -17,8 +17,19 @@
final List<DartFixSuggestion> otherSuggestions = <DartFixSuggestion>[];
final SourceChange sourceChange = new SourceChange('dartfix');
+ /// The details to be returned to the client.
+ List<String> details = [];
+
DartFixListener(this.server);
+ /// Add the given [detail] to the list of details to be returned to the
+ /// client.
+ void addDetail(String detail) {
+ if (details.length < 200) {
+ details.add(detail);
+ }
+ }
+
/// Record an edit to be sent to the client.
///
/// The associated suggestion should be separately added by calling
diff --git a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
index 62161e4..44970b6 100644
--- a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
@@ -11,8 +11,8 @@
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
-import 'package:yaml/yaml.dart';
import 'package:source_span/source_span.dart';
+import 'package:yaml/yaml.dart';
/// [NonNullableFix] visits each named type in a resolved compilation unit
/// and determines whether the associated variable or parameter can be null
@@ -143,20 +143,6 @@
}
}
- void processYamlException(String action, String optionsFilePath, error) {
- listener.addRecommendation('''Failed to $action options file
- $optionsFilePath
- $error
-
- Manually update this file to enable non-nullable by adding:
-
- analyzer:
- enable-experiment:
- - non-nullable
-''');
- _packageIsNNBD = false;
- }
-
@override
Future<void> processUnit(int phase, ResolvedUnitResult result) async {
if (!_packageIsNNBD) {
@@ -174,6 +160,20 @@
}
}
+ void processYamlException(String action, String optionsFilePath, error) {
+ listener.addRecommendation('''Failed to $action options file
+ $optionsFilePath
+ $error
+
+ Manually update this file to enable non-nullable by adding:
+
+ analyzer:
+ enable-experiment:
+ - non-nullable
+''');
+ _packageIsNNBD = false;
+ }
+
static void task(DartFixRegistrar registrar, DartFixListener listener) {
registrar.registerCodeTask(new NonNullableFix(listener));
}
@@ -185,6 +185,11 @@
NullabilityMigrationAdapter(this.listener);
@override
+ void addDetail(String detail) {
+ listener.addDetail(detail);
+ }
+
+ @override
void addEdit(SingleNullabilityFix fix, SourceEdit edit) {
listener.addEditWithoutSuggestion(fix.source, edit);
}
diff --git a/pkg/analysis_server/lib/src/nullability/graph_builder.dart b/pkg/analysis_server/lib/src/nullability/graph_builder.dart
index 232ec55..feddad2 100644
--- a/pkg/analysis_server/lib/src/nullability/graph_builder.dart
+++ b/pkg/analysis_server/lib/src/nullability/graph_builder.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/nullability/expression_checks.dart';
import 'package:analysis_server/src/nullability/node_builder.dart';
import 'package:analysis_server/src/nullability/nullability_node.dart';
+import 'package:analysis_server/src/nullability/provisional_api.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
@@ -29,7 +30,7 @@
/// previous pass over the source code).
final VariableRepository _variables;
- final bool _permissive;
+ final NullabilityMigrationListener /*?*/ listener;
final NullabilityGraph _graph;
@@ -74,7 +75,7 @@
bool _inConditionalControlFlow = false;
GraphBuilder(TypeProvider typeProvider, this._variables, this._graph,
- this._source, this._permissive)
+ this._source, this.listener)
: _notNullType =
DecoratedType(typeProvider.objectType, NullabilityNode.never),
_nonNullableBoolType =
@@ -404,10 +405,14 @@
@override
DecoratedType visitNode(AstNode node) {
- if (_permissive) {
+ if (listener != null) {
try {
return super.visitNode(node);
- } catch (_) {
+ } catch (exception, stackTrace) {
+ listener.addDetail('''
+$exception
+
+$stackTrace''');
return null;
}
} else {
diff --git a/pkg/analysis_server/lib/src/nullability/node_builder.dart b/pkg/analysis_server/lib/src/nullability/node_builder.dart
index 7d322be..6d91d13 100644
--- a/pkg/analysis_server/lib/src/nullability/node_builder.dart
+++ b/pkg/analysis_server/lib/src/nullability/node_builder.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/src/nullability/decorated_type.dart';
import 'package:analysis_server/src/nullability/expression_checks.dart';
import 'package:analysis_server/src/nullability/nullability_node.dart';
+import 'package:analysis_server/src/nullability/provisional_api.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -36,13 +37,13 @@
/// parameters?
DecoratedType _currentFunctionType;
- final bool _permissive;
+ final NullabilityMigrationListener /*?*/ listener;
final NullabilityGraph _graph;
final TypeProvider _typeProvider;
- NodeBuilder(this._variables, this._source, this._permissive, this._graph,
+ NodeBuilder(this._variables, this._source, this.listener, this._graph,
this._typeProvider);
/// Creates and stores a [DecoratedType] object corresponding to the given
@@ -98,10 +99,14 @@
@override
DecoratedType visitNode(AstNode node) {
- if (_permissive) {
+ if (listener != null) {
try {
return super.visitNode(node);
- } catch (_) {
+ } catch (exception, stackTrace) {
+ listener.addDetail('''
+$exception
+
+$stackTrace''');
return null;
}
} else {
diff --git a/pkg/analysis_server/lib/src/nullability/provisional_api.dart b/pkg/analysis_server/lib/src/nullability/provisional_api.dart
index 02b8921..bf50955 100644
--- a/pkg/analysis_server/lib/src/nullability/provisional_api.dart
+++ b/pkg/analysis_server/lib/src/nullability/provisional_api.dart
@@ -72,7 +72,7 @@
/// is fully implemented.
NullabilityMigration(this.listener, {bool permissive: false})
: _analyzerMigration =
- analyzer.NullabilityMigration(permissive: permissive);
+ analyzer.NullabilityMigration(permissive ? listener : null);
void finish() {
for (var entry in _analyzerMigration.finish().entries) {
@@ -99,6 +99,10 @@
/// [NullabilityMigrationListener] is used by [NullabilityMigration]
/// to communicate source changes or "fixes" to the client.
abstract class NullabilityMigrationListener {
+ /// Add the given [detail] to the list of details to be returned to the
+ /// client.
+ void addDetail(String detail);
+
/// [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);
diff --git a/pkg/analysis_server/lib/src/nullability/transitional_api.dart b/pkg/analysis_server/lib/src/nullability/transitional_api.dart
index 69b4d89..fc2ca3c 100644
--- a/pkg/analysis_server/lib/src/nullability/transitional_api.dart
+++ b/pkg/analysis_server/lib/src/nullability/transitional_api.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/nullability/graph_builder.dart';
import 'package:analysis_server/src/nullability/node_builder.dart';
import 'package:analysis_server/src/nullability/nullability_node.dart';
+import 'package:analysis_server/src/nullability/provisional_api.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -98,7 +99,7 @@
/// TODO(paulberry): this implementation keeps a lot of CompilationUnit objects
/// around. Can we do better?
class NullabilityMigration {
- final bool _permissive;
+ final NullabilityMigrationListener /*?*/ listener;
final Variables _variables;
@@ -110,10 +111,10 @@
/// 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.
- NullabilityMigration({bool permissive: false})
- : this._(permissive, NullabilityGraph());
+ NullabilityMigration(NullabilityMigrationListener /*?*/ listener)
+ : this._(listener, NullabilityGraph());
- NullabilityMigration._(this._permissive, this._graph)
+ NullabilityMigration._(this.listener, this._graph)
: _variables = Variables(_graph);
Map<Source, List<PotentialModification>> finish() {
@@ -122,13 +123,13 @@
}
void prepareInput(CompilationUnit unit, TypeProvider typeProvider) {
- unit.accept(NodeBuilder(_variables, unit.declaredElement.source,
- _permissive, _graph, typeProvider));
+ unit.accept(NodeBuilder(_variables, unit.declaredElement.source, listener,
+ _graph, typeProvider));
}
void processInput(CompilationUnit unit, TypeProvider typeProvider) {
unit.accept(GraphBuilder(typeProvider, _variables, _graph,
- unit.declaredElement.source, _permissive));
+ unit.declaredElement.source, listener));
}
}
diff --git a/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart b/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
index b17cff6..46e0e5b 100644
--- a/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
+++ b/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
@@ -33,7 +33,7 @@
Future<CompilationUnit> analyze(String code) async {
var unit = await super.analyze(code);
unit.accept(
- GraphBuilder(typeProvider, _variables, graph, testSource, false));
+ GraphBuilder(typeProvider, _variables, graph, testSource, null));
return unit;
}
@@ -1147,8 +1147,8 @@
Future<CompilationUnit> analyze(String code) async {
await resolveTestUnit(code);
- testUnit.accept(
- NodeBuilder(_variables, testSource, false, graph, typeProvider));
+ testUnit
+ .accept(NodeBuilder(_variables, testSource, null, graph, typeProvider));
return testUnit;
}
diff --git a/pkg/analysis_server/test/src/nullability/provisional_api_test.dart b/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
index ea1081f..c8730d7 100644
--- a/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
+++ b/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
@@ -1166,6 +1166,13 @@
class _TestMigrationListener implements NullabilityMigrationListener {
final _edits = <Source, List<SourceEdit>>{};
+ List<String> details = [];
+
+ @override
+ void addDetail(String detail) {
+ details.add(detail);
+ }
+
@override
void addEdit(SingleNullabilityFix fix, SourceEdit edit) {
(_edits[fix.source] ??= []).add(edit);