mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
Fix reporting of INSTANCE_ACCESS_TO_STATIC_MEMBER from within an extension.
Previously, if a piece of code inside an extension tried erroneously to refer to a static class member using instance access, the error CompileTimeError.UNQUALIFIED_ACCESS_TO_STATIC_MEMBER_OF_EXTENDED_TYPE would be reported. This change corrects the error to CompileTimeError.INSTANCE_ACCESS_TO_STATIC_MEMBER. In addition, the responsibility to report the error CompileTimeError.INSTANCE_ACCESS_TO_STATIC_MEMBER is shifted fully to the resolver (previously, it was split between the resolver and the error verifier). Change-Id: Idcd1a3b8a1e226fed692900838c3d2d3c0585d4f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217020 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
parent
0a8091f908
commit
189aeead47
7 changed files with 99 additions and 92 deletions
|
@ -149,19 +149,21 @@ class FunctionReferenceResolver {
|
|||
required bool implicitReceiver,
|
||||
}) {
|
||||
var enclosingElement = element.enclosingElement;
|
||||
if (_resolver.enclosingExtension != null) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode
|
||||
.UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
} else if (implicitReceiver) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
if (implicitReceiver) {
|
||||
if (_resolver.enclosingExtension != null) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode
|
||||
.UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
} else {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
|
||||
|
|
|
@ -219,19 +219,21 @@ class MethodInvocationResolver {
|
|||
bool nullReceiver,
|
||||
) {
|
||||
var enclosingElement = element.enclosingElement;
|
||||
if (_resolver.enclosingExtension != null) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode
|
||||
.UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
} else if (nullReceiver) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
if (nullReceiver) {
|
||||
if (_resolver.enclosingExtension != null) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode
|
||||
.UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
} else {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
|
||||
nameNode,
|
||||
[enclosingElement.displayName],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
|
||||
|
|
|
@ -248,18 +248,6 @@ class PropertyElementResolver {
|
|||
);
|
||||
}
|
||||
|
||||
void _checkExtensionOverrideStaticMember(
|
||||
SimpleIdentifier propertyName,
|
||||
ExecutableElement? element,
|
||||
) {
|
||||
if (element != null && element.isStatic) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
|
||||
propertyName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// If the [element] is not static, report the error on the [identifier].
|
||||
void _checkForStaticAccessToInstanceMember(
|
||||
SimpleIdentifier identifier,
|
||||
|
@ -274,6 +262,33 @@ class PropertyElementResolver {
|
|||
);
|
||||
}
|
||||
|
||||
void _checkForStaticMember(
|
||||
Expression target,
|
||||
SimpleIdentifier propertyName,
|
||||
ExecutableElement? element,
|
||||
) {
|
||||
if (element != null && element.isStatic) {
|
||||
if (target is ExtensionOverride) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
|
||||
propertyName,
|
||||
);
|
||||
} else {
|
||||
var enclosingElement = element.enclosingElement;
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
|
||||
propertyName, [
|
||||
propertyName,
|
||||
element.kind.displayName,
|
||||
enclosingElement.name ?? '<unnamed>',
|
||||
enclosingElement is ClassElement && enclosingElement.isMixin
|
||||
? 'mixin'
|
||||
: enclosingElement.kind.displayName,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DartType? _computeIndexContextType({
|
||||
required ExecutableElement? readElement,
|
||||
required ExecutableElement? writeElement,
|
||||
|
@ -417,21 +432,27 @@ class PropertyElementResolver {
|
|||
result.getter,
|
||||
result.getter?.returnType ?? _typeSystem.typeProvider.dynamicType);
|
||||
|
||||
if (hasRead && result.needsGetterError) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNDEFINED_GETTER,
|
||||
propertyName,
|
||||
[propertyName.name, targetType],
|
||||
);
|
||||
if (hasRead) {
|
||||
_checkForStaticMember(target, propertyName, result.getter);
|
||||
if (result.needsGetterError) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.UNDEFINED_GETTER,
|
||||
propertyName,
|
||||
[propertyName.name, targetType],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasWrite && result.needsSetterError) {
|
||||
AssignmentVerifier(_definingLibrary, _errorReporter).verify(
|
||||
node: propertyName,
|
||||
requested: null,
|
||||
recovery: result.getter,
|
||||
receiverTypeObject: targetType,
|
||||
);
|
||||
if (hasWrite) {
|
||||
_checkForStaticMember(target, propertyName, result.setter);
|
||||
if (result.needsSetterError) {
|
||||
AssignmentVerifier(_definingLibrary, _errorReporter).verify(
|
||||
node: propertyName,
|
||||
requested: null,
|
||||
recovery: result.getter,
|
||||
receiverTypeObject: targetType,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return PropertyElementResolverResult(
|
||||
|
@ -591,7 +612,7 @@ class PropertyElementResolver {
|
|||
[memberName, element.name],
|
||||
);
|
||||
}
|
||||
_checkExtensionOverrideStaticMember(propertyName, readElement);
|
||||
_checkForStaticMember(target, propertyName, readElement);
|
||||
}
|
||||
|
||||
ExecutableElement? writeElement;
|
||||
|
@ -604,7 +625,7 @@ class PropertyElementResolver {
|
|||
[memberName, element.name],
|
||||
);
|
||||
}
|
||||
_checkExtensionOverrideStaticMember(propertyName, writeElement);
|
||||
_checkForStaticMember(target, propertyName, writeElement);
|
||||
}
|
||||
|
||||
return PropertyElementResolverResult(
|
||||
|
@ -670,6 +691,7 @@ class PropertyElementResolver {
|
|||
|
||||
if (readElement != null) {
|
||||
readElement = _resolver.toLegacyElement(readElement);
|
||||
_checkForStaticMember(target, propertyName, readElement);
|
||||
} else {
|
||||
// We were not able to find the concrete dispatch target.
|
||||
// But we would like to give the user at least some resolution.
|
||||
|
@ -708,6 +730,7 @@ class PropertyElementResolver {
|
|||
|
||||
if (writeElement != null) {
|
||||
writeElement = _resolver.toLegacyElement(writeElement);
|
||||
_checkForStaticMember(target, propertyName, writeElement);
|
||||
} else {
|
||||
// We were not able to find the concrete dispatch target.
|
||||
// But we would like to give the user at least some resolution.
|
||||
|
|
|
@ -2658,15 +2658,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
return;
|
||||
}
|
||||
}
|
||||
errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, name, [
|
||||
name.name,
|
||||
_getKind(element),
|
||||
enclosingElement.name ?? '<unnamed>',
|
||||
enclosingElement is ClassElement && enclosingElement.isMixin
|
||||
? 'mixin'
|
||||
: enclosingElement.kind.displayName
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4856,30 +4847,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Return a human-readable representation of the kind of the [element].
|
||||
String _getKind(ExecutableElement element) {
|
||||
if (element is MethodElement) {
|
||||
return 'method';
|
||||
} else if (element is PropertyAccessorElement) {
|
||||
if (element.isSynthetic) {
|
||||
PropertyInducingElement variable = element.variable;
|
||||
if (variable is FieldElement) {
|
||||
return 'field';
|
||||
}
|
||||
return 'variable';
|
||||
} else if (element.isGetter) {
|
||||
return 'getter';
|
||||
} else {
|
||||
return 'setter';
|
||||
}
|
||||
} else if (element is ConstructorElement) {
|
||||
return 'constructor';
|
||||
} else if (element is FunctionElement) {
|
||||
return 'function';
|
||||
}
|
||||
return 'member';
|
||||
}
|
||||
|
||||
/// Return the name of the library that defines given [element].
|
||||
String _getLibraryName(Element? element) {
|
||||
if (element == null) {
|
||||
|
|
|
@ -98,6 +98,25 @@ f(C c) {
|
|||
);
|
||||
}
|
||||
|
||||
test_extension_referring_to_class_member() async {
|
||||
await assertErrorsInCode('''
|
||||
class C {
|
||||
static void m() {}
|
||||
}
|
||||
extension on int {
|
||||
foo(C c) {
|
||||
c.m(); // ERROR
|
||||
}
|
||||
}
|
||||
test(int i) {
|
||||
i.foo(C());
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, 71, 1,
|
||||
correctionContains: "class 'C'"),
|
||||
]);
|
||||
}
|
||||
|
||||
test_extension_setter() async {
|
||||
await assertErrorsInCode('''
|
||||
class C {}
|
||||
|
|
|
@ -15,7 +15,6 @@ class Example {
|
|||
// [cfe] Setter not found: 'nextVar'.
|
||||
this.nextVar = 1;
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
|
||||
// [cfe] The setter 'nextVar' isn't defined for the class 'Example'.
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
|
||||
|
@ -30,8 +29,6 @@ class Example {
|
|||
// [analyzer] COMPILE_TIME_ERROR.INVALID_REFERENCE_TO_THIS
|
||||
// [cfe] Expected identifier, but got 'this'.
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ class Example {
|
|||
// [cfe] Setter not found: 'nextVar'.
|
||||
this.nextVar = 1;
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
|
||||
// [cfe] The setter 'nextVar' isn't defined for the class 'Example'.
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
|
||||
|
@ -32,8 +31,6 @@ class Example {
|
|||
// [analyzer] COMPILE_TIME_ERROR.INVALID_REFERENCE_TO_THIS
|
||||
// [cfe] Expected identifier, but got 'this'.
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
|
||||
// ^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue