Improve the feedback for unimplemented portions of the migration tooling

Change-Id: I1d4fd85f15c16e74e4dfdf5a618de2a7f4f3ec9a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106680
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Dan Rubel <danrubel@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Brian Wilkerson 2019-06-19 17:34:26 +00:00 committed by commit-bot@chromium.org
parent a421022b77
commit 837d28b0cb
2 changed files with 105 additions and 35 deletions

View file

@ -145,7 +145,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
@override
DecoratedType visitAsExpression(AsExpression node) {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'AsExpression');
}
@override
@ -166,7 +167,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
@override
DecoratedType visitAssignmentExpression(AssignmentExpression node) {
if (node.operator.type != TokenType.EQ) {
throw UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(node, 'Assignment with operator ${node.operator.lexeme}');
}
var leftType = node.leftHandSide.accept(this);
var conditionalNode = _lastConditionalNode;
@ -227,8 +229,9 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
calleeType.positionalParameters[0], node.rightOperand);
return calleeType.returnType;
default:
assert(false); // TODO(paulberry)
return null;
// TODO(paulberry)
_unimplemented(
node, 'Binary expression with operator ${node.operator.lexeme}');
}
}
@ -314,13 +317,15 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
@override
DecoratedType visitFunctionExpression(FunctionExpression node) {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'FunctionExpression');
}
@override
DecoratedType visitFunctionExpressionInvocation(
FunctionExpressionInvocation node) {
throw UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'FunctionExpressionInvocation');
}
@override
@ -369,7 +374,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
}
var callee = node.staticElement;
if (callee == null) {
throw new UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(node, 'Index expression with no static type');
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
// TODO(paulberry): substitute if necessary
@ -389,7 +395,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
if (callee.enclosingElement.typeParameters.isNotEmpty) {
// If the class has type parameters then we might need to substitute the
// appropriate type arguments.
throw UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Instance creation expression with type arguments');
}
_handleInvocationArguments(node.argumentList, calleeType);
return calleeType.returnType;
@ -406,9 +413,11 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
if (type is NamedType && type.typeArguments != null) {
// TODO(brianwilkerson) Figure out what constraints we need to add to
// allow the tool to decide whether to make the type arguments nullable.
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Is expression with type arguments');
} else if (type is GenericFunctionType) {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Is expression with GenericFunctionType');
}
node.visitChildren(this);
return DecoratedType(node.staticType, _graph.never);
@ -421,7 +430,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
// TODO(brianwilkerson) We might want to create a fake node in the graph
// to represent the type argument so that we can still create edges from
// the elements to it.
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'List literal with no type arguments');
} else {
var typeArgumentType = _variables.decoratedTypeAnnotation(
_source, node.typeArguments.arguments[0]);
@ -431,7 +441,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
} else {
// Handle spread and control flow elements.
element.accept(this);
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Spread or control flow element');
}
}
return DecoratedType(listType, _graph.never,
@ -469,7 +480,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
}
var callee = node.methodName.staticElement;
if (callee == null) {
throw UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(node, 'Unresolved method name');
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
// TODO(paulberry): substitute if necessary
@ -518,13 +530,15 @@ $stackTrace''');
@override
DecoratedType visitPostfixExpression(PostfixExpression node) {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'PostfixExpression');
}
@override
DecoratedType visitPrefixedIdentifier(PrefixedIdentifier node) {
if (node.prefix.staticElement is ImportElement) {
throw new UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(node, 'PrefixedIdentifier with a prefix');
} else {
return _handlePropertyAccess(node, node.prefix, node.identifier);
}
@ -538,7 +552,8 @@ $stackTrace''');
return _nonNullableBoolType;
}
// TODO(brianwilkerson) The remaining cases are invocations.
throw new UnimplementedError('TODO(brianwilkerson)');
_unimplemented(
node, 'Prefix expression with operator ${node.operator.lexeme}');
}
@override
@ -565,7 +580,8 @@ $stackTrace''');
// TODO(brianwilkerson) We might want to create fake nodes in the graph to
// represent the type arguments so that we can still create edges from
// the elements to them.
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Set or map literal with no type arguments');
} else if (typeArguments.length == 1) {
var elementType =
_variables.decoratedTypeAnnotation(_source, typeArguments[0]);
@ -575,7 +591,8 @@ $stackTrace''');
} else {
// Handle spread and control flow elements.
element.accept(this);
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Spread or control flow element');
}
}
return DecoratedType(listType, _graph.never,
@ -592,13 +609,16 @@ $stackTrace''');
} else {
// Handle spread and control flow elements.
element.accept(this);
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Spread or control flow element');
}
}
return DecoratedType(listType, _graph.never,
typeArguments: [keyType, valueType]);
} else {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(
node, 'Set or map literal with more than two type arguments');
}
}
@ -612,7 +632,8 @@ $stackTrace''');
return _nonNullableTypeType;
} else {
// TODO(paulberry)
throw new UnimplementedError('${staticElement.runtimeType}');
_unimplemented(node,
'Simple identifier with a static element of type ${staticElement.runtimeType}');
}
}
@ -685,7 +706,8 @@ $stackTrace''');
var destinationType = getOrComputeElementType(node.declaredElement);
var initializer = node.initializer;
if (initializer == null) {
throw UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(node, 'Variable declaration with no initializer');
} else {
_handleAssignment(destinationType, initializer);
}
@ -769,13 +791,15 @@ $stackTrace''');
var name = expression.name.label.name;
var parameterType = calleeType.namedParameters[name];
if (parameterType == null) {
throw UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(expression, 'Missing type for named parameter');
}
_handleAssignment(parameterType, expression.expression);
suppliedNamedParameters.add(name);
} else {
if (calleeType.positionalParameters.length <= i) {
throw UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(argumentList, 'Missing positional parameter at $i');
}
_handleAssignment(calleeType.positionalParameters[i++], expression);
}
@ -800,7 +824,8 @@ $stackTrace''');
}
var callee = propertyName.staticElement;
if (callee == null) {
throw new UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(node, 'Unresolved property access');
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
// TODO(paulberry): substitute if necessary
@ -837,7 +862,9 @@ $stackTrace''');
case TokenType.QUESTION_PERIOD:
return true;
default:
throw new UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(
expression, 'Conditional expression with operator ${token.lexeme}');
}
}
@ -865,6 +892,21 @@ $stackTrace''');
return false;
}
@alwaysThrows
void _unimplemented(AstNode node, String message) {
CompilationUnit unit = node.root as CompilationUnit;
StringBuffer buffer = StringBuffer();
buffer.write(message);
buffer.write(' in "');
buffer.write(node.toSource());
buffer.write('" on line ');
buffer.write(unit.lineInfo.getLocation(node.offset).lineNumber);
buffer.write(' of "');
buffer.write(unit.declaredElement.source.fullName);
buffer.write('"');
throw UnimplementedError(buffer.toString());
}
void _unionDecoratedTypes(
DecoratedType x, DecoratedType y, EdgeOrigin origin) {
_graph.union(x.node, y.node, origin);
@ -876,7 +918,8 @@ $stackTrace''');
y.positionalParameters.isNotEmpty ||
x.namedParameters.isNotEmpty ||
y.namedParameters.isNotEmpty) {
throw UnimplementedError('TODO(paulberry): _unionDecoratedTypes($x, $y)');
// TODO(paulberry)
throw UnimplementedError('_unionDecoratedTypes($x, $y, $origin)');
}
}
}

View file

@ -10,6 +10,7 @@ import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:front_end/src/scanner/token.dart';
import 'package:meta/meta.dart';
import 'package:nnbd_migration/nnbd_migration.dart';
import 'package:nnbd_migration/src/conditional_discard.dart';
import 'package:nnbd_migration/src/decorated_type.dart';
@ -69,7 +70,8 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType> {
if (node.factoryKeyword != null) {
// Factory constructors can return null, but we don't want to propagate a
// null type if we can prove that null is never returned.
throw UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'Declaration of a factory constructor');
}
_handleExecutableDeclaration(
node.declaredElement, null, node.parameters, node.body, node);
@ -93,7 +95,8 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType> {
@override
DecoratedType visitFieldFormalParameter(FieldFormalParameter node) {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'FieldFormalParameter');
}
@override
@ -117,13 +120,15 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType> {
@override
DecoratedType visitFunctionTypeAlias(FunctionTypeAlias node) {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'FunctionTypeAlias');
}
@override
DecoratedType visitFunctionTypedFormalParameter(
FunctionTypedFormalParameter node) {
throw new UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(node, 'FunctionTypedFormalParameter');
}
@override
@ -197,7 +202,8 @@ $stackTrace''');
if (node is GenericFunctionType) {
returnType = decorateType(node.returnType, node);
if (node.typeParameters != null) {
throw UnimplementedError('TODO(paulberry)');
// TODO(paulberry)
_unimplemented(node, 'Generic function type with type parameters');
}
positionalParameters = <DecoratedType>[];
namedParameters = <String, DecoratedType>{};
@ -281,7 +287,9 @@ $stackTrace''');
typeArguments:
type.typeArguments.map(_decorateImplicitTypeArgument).toList());
}
throw UnimplementedError('TODO(paulberry): ${type.runtimeType}');
// TODO(paulberry)
throw UnimplementedError(
'_decorateImplicitTypeArgument(${type.runtimeType})');
}
/// Common handling of function and method declarations.
@ -298,11 +306,15 @@ $stackTrace''');
if (declaredElement.isFactory) {
// Factory constructors can return null, but we don't want to propagate
// a null type if we can prove that null is never returned.
throw UnimplementedError('TODO(brianwilkerson)');
// TODO(brianwilkerson)
_unimplemented(
parameters.parent, 'Declaration of a factory constructor');
}
if (declaredElement.enclosingElement.typeParameters.isNotEmpty) {
// Need to decorate the type parameters appropriately.
throw new UnimplementedError('TODO(paulberry,brianwilkerson)');
// TODO(paulberry,brianwilkerson)
_unimplemented(parameters.parent,
'Declaration of a constructor with type parameters');
}
decoratedReturnType = new DecoratedType(
declaredElement.enclosingElement.type, _graph.never);
@ -327,6 +339,21 @@ $stackTrace''');
}
_variables.recordDecoratedElementType(declaredElement, functionType);
}
@alwaysThrows
void _unimplemented(AstNode node, String message) {
CompilationUnit unit = node.root as CompilationUnit;
StringBuffer buffer = StringBuffer();
buffer.write(message);
buffer.write(' in "');
buffer.write(node.toSource());
buffer.write('" on line ');
buffer.write(unit.lineInfo.getLocation(node.offset).lineNumber);
buffer.write(' of "');
buffer.write(unit.declaredElement.source.fullName);
buffer.write('"');
throw UnimplementedError(buffer.toString());
}
}
/// Repository of constraint variables and decorated types corresponding to the