diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart index e9fdd4d12c6..0e34466dd5c 100644 --- a/pkg/analyzer/lib/error/error.dart +++ b/pkg/analyzer/lib/error/error.dart @@ -65,6 +65,7 @@ const List errorCodeValues = const [ CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, CompileTimeErrorCode.ACCESS_PRIVATE_ENUM_FIELD, + CompileTimeErrorCode.ACCESS_STATIC_EXTENSION_MEMBER, CompileTimeErrorCode.AMBIGUOUS_EXPORT, CompileTimeErrorCode.AMBIGUOUS_EXTENSION_METHOD_ACCESS, CompileTimeErrorCode.AMBIGUOUS_SET_OR_MAP_LITERAL_BOTH, diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart index 002a40208b5..abed06fd813 100644 --- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart @@ -299,6 +299,10 @@ class MethodInvocationResolver { return invokeType; } + /// Ask the type system to instantiate the given type to its bounds. + DartType _instantiateToBounds(DartType type) => + _resolver.typeSystem.instantiateToBounds(type); + bool _isCoreFunction(DartType type) { // TODO(scheglov) Can we optimize this? return type is InterfaceType && type.isDartCoreFunction; @@ -413,6 +417,23 @@ class MethodInvocationResolver { return null; } + void _resolveExtension(MethodInvocation node, ExtensionElement extension, + SimpleIdentifier nameNode, String name) { + ExecutableElement member = extension.getMethod(name) ?? + extension.getGetter(name) ?? + extension.getSetter(name); + if (member.isStatic) { + _setDynamicResolution(node); + _resolver.errorReporter.reportErrorForNode( + CompileTimeErrorCode.ACCESS_STATIC_EXTENSION_MEMBER, + nameNode, + ); + return; + } + nameNode.staticElement = member; + return; + } + void _resolveExtensionOverride(MethodInvocation node, ExtensionOverride override, SimpleIdentifier nameNode, String name) { ExtensionElement element = override.extensionName.staticElement; @@ -499,12 +520,7 @@ class MethodInvocationResolver { List extensions = _getApplicableExtensions(receiverType, name); if (extensions.length == 1) { - var extension = extensions[0]; - Element member = extension.getMethod(name) ?? - extension.getGetter(name) ?? - extension.getSetter(name); - nameNode.staticElement = member; - return; + return _resolveExtension(node, extensions[0], nameNode, name); } else if (extensions.length > 1) { ExtensionElement extension = _chooseMostSpecificExtension(extensions, receiverType); @@ -521,11 +537,7 @@ class MethodInvocationResolver { ); return; } else { - ExecutableElement member = extension.getMethod(name) ?? - extension.getGetter(name) ?? - extension.getSetter(name); - nameNode.staticElement = member; - return; + return _resolveExtension(node, extension, nameNode, name); } } @@ -788,10 +800,6 @@ class MethodInvocationResolver { _reportInvocationOfNonFunction(node); } - /// Ask the type system to instantiate the given type to its bounds. - DartType _instantiateToBounds(DartType type) => - _resolver.typeSystem.instantiateToBounds(type); - /// Ask the type system for a subtype check. bool _subtypeOf(DartType type1, DartType type2) => _resolver.typeSystem.isSubtypeOf(type1, type2); diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart index 6a28520a086..c32e3075033 100644 --- a/pkg/analyzer/lib/src/error/codes.dart +++ b/pkg/analyzer/lib/src/error/codes.dart @@ -125,6 +125,15 @@ class CompileTimeErrorCode extends ErrorCode { "The private fields of an enum can't be accessed, even within the " "same library."); + /** + * No parameters. + */ + //todo (pq): refactor to reuse StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER. + static const CompileTimeErrorCode ACCESS_STATIC_EXTENSION_MEMBER = + const CompileTimeErrorCode('ACCESS_STATIC_EXTENSION_MEMBER', + "Static extension members can't be accessed.", + correction: "Try removing the static member access."); + /** * 14.2 Exports: It is a compile-time error if a name N is re-exported * by a library L and N is introduced into the export namespace diff --git a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart index e4c16a4b1c7..ab82534f463 100644 --- a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart @@ -115,6 +115,23 @@ f() { expect(invocation.methodName.staticElement, declaration.declaredElement); } + test_method_resolvesToStatic() async { + await assertErrorsInCode(''' +class A { } + +extension A1_Ext on A { + static void a() { } +} + +f() { + A a = A(); + a.a(); +} +''', [ + error(CompileTimeErrorCode.ACCESS_STATIC_EXTENSION_MEMBER, 85, 1), + ]); + } + test_method_specificSubtypeMatchLocal() async { await assertNoErrorsInCode(''' class A { }