Add diagnostic for undefined getters and setters invoked on an extension override
Change-Id: Ib66f203836e3900e2e151dd3a8b6be1360e12d50 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109319 Reviewed-by: Phil Quitslund <pquitslund@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
@@ -290,7 +290,9 @@ const List<ErrorCode> errorCodeValues = const [
|
||||
CompileTimeErrorCode.UNDEFINED_CLASS,
|
||||
CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER,
|
||||
CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT,
|
||||
CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
|
||||
CompileTimeErrorCode.UNDEFINED_EXTENSION_METHOD,
|
||||
CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
|
||||
CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER,
|
||||
CompileTimeErrorCode.URI_DOES_NOT_EXIST,
|
||||
CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED,
|
||||
|
||||
@@ -3115,15 +3115,39 @@ class CompileTimeErrorCode extends ErrorCode {
|
||||
|
||||
/**
|
||||
* Parameters:
|
||||
* 0: the name of the extension method that is undefined
|
||||
* 0: the name of the getter that is undefined
|
||||
* 1: the name of the extension that was explicitly specified
|
||||
*/
|
||||
static const CompileTimeErrorCode UNDEFINED_EXTENSION_GETTER =
|
||||
const CompileTimeErrorCode('UNDEFINED_EXTENSION_GETTER',
|
||||
"The getter '{0}' isn't defined for the extension '{1}'.",
|
||||
correction:
|
||||
"Try correcting the name to the name of an existing getter, or "
|
||||
"defining a getter named '{0}'.");
|
||||
|
||||
/**
|
||||
* Parameters:
|
||||
* 0: the name of the method that is undefined
|
||||
* 1: the name of the extension that was explicitly specified
|
||||
*/
|
||||
static const CompileTimeErrorCode UNDEFINED_EXTENSION_METHOD =
|
||||
const CompileTimeErrorCode('UNDEFINED_EXTENSION_METHOD',
|
||||
"The extension method '{0}' isn't defined for the extension '{1}'.",
|
||||
"The method '{0}' isn't defined for the extension '{1}'.",
|
||||
correction:
|
||||
"Try correcting the name to the name of an existing method, or "
|
||||
"defining an extension method named '{0}'.");
|
||||
"defining a method named '{0}'.");
|
||||
|
||||
/**
|
||||
* Parameters:
|
||||
* 0: the name of the setter that is undefined
|
||||
* 1: the name of the extension that was explicitly specified
|
||||
*/
|
||||
static const CompileTimeErrorCode UNDEFINED_EXTENSION_SETTER =
|
||||
const CompileTimeErrorCode('UNDEFINED_EXTENSION_SETTER',
|
||||
"The setter '{0}' isn't defined for the extension '{1}'.",
|
||||
correction:
|
||||
"Try correcting the name to the name of an existing setter, or "
|
||||
"defining a setter named '{0}'.");
|
||||
|
||||
/**
|
||||
* 12.14.2 Binding Actuals to Formals: Furthermore, each <i>q<sub>i</sub></i>,
|
||||
|
||||
@@ -685,25 +685,31 @@ class ElementResolver extends SimpleAstVisitor<void> {
|
||||
if (propertyName.inSetterContext()) {
|
||||
member = element.getSetter(propertyName.name);
|
||||
if (member == null) {
|
||||
// TODO(brianwilkerson) Report this error.
|
||||
throw new UnsupportedError('extension override of missing setter');
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
|
||||
propertyName,
|
||||
[propertyName.name, element.name]);
|
||||
}
|
||||
if (propertyName.inGetterContext()) {
|
||||
PropertyAccessorElement getter = element.getGetter(propertyName.name);
|
||||
if (getter == null) {
|
||||
// TODO(brianwilkerson) Report this error.
|
||||
throw new UnsupportedError('extension override of missing getter');
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
|
||||
propertyName,
|
||||
[propertyName.name, element.name]);
|
||||
}
|
||||
propertyName.auxiliaryElements = AuxiliaryElements(getter, null);
|
||||
}
|
||||
} else if (propertyName.inGetterContext()) {
|
||||
member = element.getGetter(propertyName.name);
|
||||
if (member == null) {
|
||||
// TODO(brianwilkerson) Report this error.
|
||||
throw new UnsupportedError('extension override of missing getter');
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
|
||||
propertyName,
|
||||
[propertyName.name, element.name]);
|
||||
}
|
||||
}
|
||||
if (member.isStatic) {
|
||||
if (member != null && member.isStatic) {
|
||||
// TODO(brianwilkerson) Report this error.
|
||||
throw new UnsupportedError('extension override of static member');
|
||||
}
|
||||
|
||||
@@ -185,7 +185,9 @@ import 'type_check_is_not_null_test.dart' as type_check_is_not_null;
|
||||
import 'type_check_is_null_test.dart' as type_check_is_null;
|
||||
import 'unchecked_use_of_nullable_value_test.dart'
|
||||
as unchecked_use_of_nullable_value;
|
||||
import 'undefined_extension_getter_test.dart' as undefined_extension_getter;
|
||||
import 'undefined_extension_method_test.dart' as undefined_extension_method;
|
||||
import 'undefined_extension_setter_test.dart' as undefined_extension_setter;
|
||||
import 'undefined_getter_test.dart' as undefined_getter;
|
||||
import 'undefined_hidden_name_test.dart' as undefined_hidden_name;
|
||||
import 'undefined_identifier_test.dart' as undefined_identifier;
|
||||
@@ -346,7 +348,9 @@ main() {
|
||||
type_check_is_not_null.main();
|
||||
type_check_is_null.main();
|
||||
unchecked_use_of_nullable_value.main();
|
||||
undefined_extension_getter.main();
|
||||
undefined_extension_method.main();
|
||||
undefined_extension_setter.main();
|
||||
undefined_getter.main();
|
||||
undefined_identifier.main();
|
||||
undefined_hidden_name.main();
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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:analyzer/dart/analysis/features.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/driver_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(UndefinedExtensionGetterTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class UndefinedExtensionGetterTest extends DriverResolutionTest {
|
||||
@override
|
||||
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
|
||||
..contextFeatures = new FeatureSet.forTesting(
|
||||
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
|
||||
|
||||
test_defined() {
|
||||
assertNoErrorsInCode('''
|
||||
extension E on String {
|
||||
int get g => 0;
|
||||
}
|
||||
f() {
|
||||
E('a').g;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_undefined() {
|
||||
assertErrorsInCode('''
|
||||
extension E on String {}
|
||||
f() {
|
||||
E('a').g;
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER, 40, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_undefined_withSetter() {
|
||||
assertErrorsInCode('''
|
||||
extension E on String {
|
||||
void set s(int x) {}
|
||||
}
|
||||
f() {
|
||||
E('a').s += 1;
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER, 64, 1),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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:analyzer/dart/analysis/features.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/driver_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(UndefinedExtensionSetterTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class UndefinedExtensionSetterTest extends DriverResolutionTest {
|
||||
@override
|
||||
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
|
||||
..contextFeatures = new FeatureSet.forTesting(
|
||||
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
|
||||
|
||||
test_defined() {
|
||||
assertNoErrorsInCode('''
|
||||
extension E on String {
|
||||
void set s(int x) {}
|
||||
}
|
||||
f() {
|
||||
E('a').s = 1;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_undefined() {
|
||||
assertErrorsInCode('''
|
||||
extension E on String {}
|
||||
f() {
|
||||
E('a').s = 1;
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER, 40, 1),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user