From 60734895390ce67ca81ef01860ba76031fa0cec4 Mon Sep 17 00:00:00 2001 From: Brian Wilkerson Date: Wed, 17 Jul 2019 12:36:16 +0000 Subject: [PATCH] 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 Reviewed-by: Konstantin Shcheglov --- pkg/analyzer/lib/error/error.dart | 2 + pkg/analyzer/lib/src/error/codes.dart | 30 +++++++++- .../lib/src/generated/element_resolver.dart | 20 ++++--- .../test/src/diagnostics/test_all.dart | 4 ++ .../undefined_extension_getter_test.dart | 59 +++++++++++++++++++ .../undefined_extension_setter_test.dart | 46 +++++++++++++++ 6 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart create mode 100644 pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart index 7ddffacdd7e..3bb4b7ba9ee 100644 --- a/pkg/analyzer/lib/error/error.dart +++ b/pkg/analyzer/lib/error/error.dart @@ -290,7 +290,9 @@ const List 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, diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart index f6b9a4d99d3..6be1aaa3493 100644 --- a/pkg/analyzer/lib/src/error/codes.dart +++ b/pkg/analyzer/lib/src/error/codes.dart @@ -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 qi, diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart index b9ee6194169..e6fcca8000a 100644 --- a/pkg/analyzer/lib/src/generated/element_resolver.dart +++ b/pkg/analyzer/lib/src/generated/element_resolver.dart @@ -685,25 +685,31 @@ class ElementResolver extends SimpleAstVisitor { 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'); } diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index fcdef98a1fd..77b399b1ab9 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart @@ -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(); diff --git a/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart new file mode 100644 index 00000000000..6c8fe6be9d6 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/undefined_extension_getter_test.dart @@ -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), + ]); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart new file mode 100644 index 00000000000..be050627568 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/undefined_extension_setter_test.dart @@ -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), + ]); + } +}