Analyzer: print constructor name when constructor returns invalid type

Fixes https://github.com/dart-lang/sdk/issues/27387

Change-Id: I8ce81bab4c4601c5157977d3f43f73903dae7f8b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151200
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Sam Rawlins 2020-06-15 13:52:56 +00:00 committed by commit-bot@chromium.org
parent d87046342f
commit 294a2cffd1
7 changed files with 78 additions and 4 deletions

View file

@ -706,6 +706,7 @@ const List<ErrorCode> errorCodeValues = [
// ignore: deprecated_member_use_from_same_package
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CONSTRUCTOR,
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION,
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_METHOD,
StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND,

View file

@ -7340,6 +7340,20 @@ class StaticTypeWarningCode extends AnalyzerErrorCode {
"context.",
hasPublishedDocs: true);
/**
* Parameters:
* 0: the return type as declared in the return statement
* 1: the expected return type as defined by the enclosing class
* 2: the name of the constructor
*/
static const StaticTypeWarningCode RETURN_OF_INVALID_TYPE_FROM_CONSTRUCTOR =
StaticTypeWarningCodeWithUniqueName(
'RETURN_OF_INVALID_TYPE',
'StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CONSTRUCTOR',
"A value of type '{0}' can't be returned from constructor '{2}' "
"because it has a return type of '{1}'.",
hasPublishedDocs: true);
/**
* Parameters:
* 0: the return type as declared in the return statement

View file

@ -141,7 +141,19 @@ class ReturnTypeVerifier {
void reportTypeError() {
String displayName = enclosingExecutable.element.displayName;
if (displayName.isEmpty) {
if (enclosingExecutable.isConstructor) {
var constructor = enclosingExecutable.element as ConstructorElement;
var className = constructor.enclosingElement.displayName;
var constructorBaseName = constructor.displayName;
var constructorName = constructorBaseName.isEmpty
? className
: '$className.$constructorBaseName';
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CONSTRUCTOR,
expression,
[S, T, constructorName],
);
} else if (displayName.isEmpty) {
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
expression,
@ -237,7 +249,19 @@ class ReturnTypeVerifier {
void reportTypeError() {
String displayName = enclosingExecutable.element.displayName;
if (displayName.isEmpty) {
if (enclosingExecutable.isConstructor) {
var constructor = enclosingExecutable.element as ConstructorElement;
var className = constructor.enclosingElement.displayName;
var constructorBaseName = constructor.displayName;
var constructorName = constructorBaseName.isEmpty
? className
: '$className.$constructorBaseName';
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CONSTRUCTOR,
expression,
[S, T, constructorName],
);
} else if (displayName.isEmpty) {
_errorReporter.reportErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
expression,

View file

@ -71,6 +71,8 @@ class EnclosingExecutableContext {
EnclosingExecutableContext.empty() : this(null);
bool get isConstructor => element is ConstructorElement;
bool get isMethod => element is MethodElement;
bool get isSynchronous => !isAsynchronous;

View file

@ -17,6 +17,39 @@ main() {
@reflectiveTest
class ReturnOfInvalidTypeTest extends DriverResolutionTest {
test_closure() async {
await assertErrorsInCode('''
typedef Td = int Function();
Td f() {
return () => "hello";
}
''', [
error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE, 53, 7),
]);
}
test_factoryConstructor_named() async {
await assertErrorsInCode('''
class C {
factory C.named() => 7;
}
''', [
error(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CONSTRUCTOR, 33, 1),
]);
}
test_factoryConstructor_unnamed() async {
await assertErrorsInCode('''
class C {
factory C() => 7;
}
''', [
error(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CONSTRUCTOR, 27, 1),
]);
}
test_function_async_block__to_Future_void() async {
await assertNoErrorsInCode(r'''
Future<void> f1() async {}

View file

@ -7,7 +7,7 @@ import "package:expect/expect.dart";
class A {
factory A() => 42;
// ^^
// [analyzer] STATIC_TYPE_WARNING.RETURN_OF_INVALID_TYPE_FROM_CLOSURE
// [analyzer] STATIC_TYPE_WARNING.RETURN_OF_INVALID_TYPE
// [cfe] A value of type 'int' can't be assigned to a variable of type 'A'.
}

View file

@ -7,7 +7,7 @@ import "package:expect/expect.dart";
class A {
factory A() => 42;
// ^^
// [analyzer] STATIC_TYPE_WARNING.RETURN_OF_INVALID_TYPE_FROM_CLOSURE
// [analyzer] STATIC_TYPE_WARNING.RETURN_OF_INVALID_TYPE
// [cfe] A value of type 'int' can't be assigned to a variable of type 'A'.
}