mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 15:21:19 +00:00
Extract and rewrite MethodInvocation resolution.
This is a copy of https://dart-review.googlesource.com/c/sdk/+/78182, but now in the analyzer branch. R=brianwilkerson@google.com, paulberry@google.com Change-Id: I75d17a351ee7a33c164d560009cf3ffd088d956a Reviewed-on: https://dart-review.googlesource.com/c/80942 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
108101149e
commit
c44fa48f8f
|
@ -62,7 +62,6 @@ bool hasFix(ErrorCode errorCode) =>
|
|||
errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
|
||||
errorCode == HintCode.UNUSED_CATCH_STACK ||
|
||||
errorCode == HintCode.UNUSED_IMPORT ||
|
||||
errorCode == HintCode.UNDEFINED_METHOD ||
|
||||
errorCode == ParserErrorCode.EXPECTED_TOKEN ||
|
||||
errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS ||
|
||||
errorCode == ParserErrorCode.VAR_AS_TYPE_NAME ||
|
||||
|
|
|
@ -524,8 +524,7 @@ class FixProcessor {
|
|||
await _addFix_importLibrary_withTopLevelVariable();
|
||||
await _addFix_importLibrary_withType();
|
||||
}
|
||||
if (errorCode == HintCode.UNDEFINED_METHOD ||
|
||||
errorCode == StaticTypeWarningCode.UNDEFINED_METHOD) {
|
||||
if (errorCode == StaticTypeWarningCode.UNDEFINED_METHOD) {
|
||||
await _addFix_createClass();
|
||||
await _addFix_importLibrary_withFunction();
|
||||
await _addFix_importLibrary_withType();
|
||||
|
|
|
@ -314,7 +314,6 @@ const List<ErrorCode> errorCodeValues = const [
|
|||
HintCode.TYPE_CHECK_IS_NULL,
|
||||
HintCode.UNDEFINED_GETTER,
|
||||
HintCode.UNDEFINED_HIDDEN_NAME,
|
||||
HintCode.UNDEFINED_METHOD,
|
||||
HintCode.UNDEFINED_OPERATOR,
|
||||
HintCode.UNDEFINED_SETTER,
|
||||
HintCode.UNDEFINED_SHOWN_NAME,
|
||||
|
|
|
@ -557,21 +557,6 @@ class HintCode extends ErrorCode {
|
|||
"The library '{0}' doesn't export a member with the hidden name '{1}'.",
|
||||
correction: "Try removing the name from the list of hidden members.");
|
||||
|
||||
/**
|
||||
* This hint is generated anywhere where the
|
||||
* [StaticTypeWarningCode.UNDEFINED_METHOD] would have been generated, if we
|
||||
* used propagated information for the warnings.
|
||||
*
|
||||
* Parameters:
|
||||
* 0: the name of the method that is undefined
|
||||
* 1: the resolved type name that the method lookup is happening on
|
||||
*/
|
||||
static const HintCode UNDEFINED_METHOD = const HintCode(
|
||||
'UNDEFINED_METHOD', "The method '{0}' isn't defined for the class '{1}'.",
|
||||
correction:
|
||||
"Try correcting the name to the name of an existing method, or "
|
||||
"defining a method named '{0}'.");
|
||||
|
||||
/**
|
||||
* This hint is generated anywhere where the
|
||||
* [StaticTypeWarningCode.UNDEFINED_OPERATOR] would have been generated, if we
|
||||
|
|
|
@ -0,0 +1,638 @@
|
|||
// Copyright (c) 2018, 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/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/token.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
|
||||
import 'package:analyzer/src/dart/element/member.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/resolver/scope.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/resolver.dart';
|
||||
|
||||
class MethodInvocationResolver {
|
||||
static final _nameCall = new Name(null, 'call');
|
||||
|
||||
/// The resolver driving this participant.
|
||||
final ResolverVisitor _resolver;
|
||||
|
||||
/// The type representing the type 'dynamic'.
|
||||
final DynamicTypeImpl _dynamicType = DynamicTypeImpl.instance;
|
||||
|
||||
/// The type representing the type 'type'.
|
||||
final InterfaceType _typeType;
|
||||
|
||||
/// The manager for the inheritance mappings.
|
||||
final InheritanceManager2 _inheritance;
|
||||
|
||||
/// The element for the library containing the compilation unit being visited.
|
||||
final LibraryElement _definingLibrary;
|
||||
|
||||
/// The object keeping track of which elements have had their types promoted.
|
||||
TypePromotionManager _promoteManager;
|
||||
|
||||
MethodInvocationResolver(this._resolver)
|
||||
: _typeType = _resolver.typeProvider.typeType,
|
||||
_inheritance = _resolver.inheritance,
|
||||
_definingLibrary = _resolver.definingLibrary,
|
||||
_promoteManager = _resolver.promoteManager;
|
||||
|
||||
/// The scope used to resolve identifiers.
|
||||
Scope get nameScope => _resolver.nameScope;
|
||||
|
||||
void resolve(MethodInvocation node) {
|
||||
SimpleIdentifier nameNode = node.methodName;
|
||||
String name = nameNode.name;
|
||||
|
||||
//
|
||||
// Synthetic identifiers have been already reported during parsing.
|
||||
//
|
||||
if (nameNode.isSynthetic) {
|
||||
return;
|
||||
}
|
||||
|
||||
Expression receiver = node.realTarget;
|
||||
|
||||
if (receiver == null) {
|
||||
_resolveReceiverNull(node, nameNode, name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiver is NullLiteral) {
|
||||
_setDynamicResolution(node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiver is SimpleIdentifier) {
|
||||
var receiverElement = receiver.staticElement;
|
||||
if (receiverElement is PrefixElement) {
|
||||
_resolveReceiverPrefix(node, receiver, receiverElement, nameNode, name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (receiver is SuperExpression) {
|
||||
_resolveReceiverSuper(node, receiver, nameNode, name);
|
||||
return;
|
||||
}
|
||||
|
||||
ClassElement typeReference = getTypeReference(receiver);
|
||||
if (typeReference != null) {
|
||||
_resolveReceiverTypeLiteral(node, typeReference, nameNode, name);
|
||||
return;
|
||||
}
|
||||
|
||||
DartType receiverType = receiver.staticType;
|
||||
receiverType = _resolveTypeParameter(receiverType);
|
||||
|
||||
if (receiverType is InterfaceType) {
|
||||
_resolveReceiverInterfaceType(node, receiverType, nameNode, name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiverType is DynamicTypeImpl) {
|
||||
_resolveReceiverDynamic(node, name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiverType is FunctionType) {
|
||||
_resolveReceiverFunctionType(
|
||||
node, receiver, receiverType, nameNode, name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (receiverType is VoidType) {
|
||||
_reportUseOfVoidType(node, receiver);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// Given an [argumentList] and the executable [element] that will be invoked
|
||||
/// using those arguments, compute the list of parameters that correspond to
|
||||
/// the list of arguments. Return the parameters that correspond to the
|
||||
/// arguments, or `null` if no correspondence could be computed.
|
||||
List<ParameterElement> _computeCorrespondingParameters(
|
||||
ArgumentList argumentList, DartType type) {
|
||||
if (type is InterfaceType) {
|
||||
MethodElement callMethod =
|
||||
type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
|
||||
if (callMethod != null) {
|
||||
return _resolveArgumentsToFunction(false, argumentList, callMethod);
|
||||
}
|
||||
} else if (type is FunctionType) {
|
||||
return _resolveArgumentsToParameters(
|
||||
false, argumentList, type.parameters);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
DartType _getCalleeType(FunctionType targetType) {
|
||||
if (targetType.element.kind == ElementKind.GETTER) {
|
||||
var calleeType = (targetType as FunctionTypeImpl).returnType;
|
||||
calleeType = _resolveTypeParameter(calleeType);
|
||||
return calleeType;
|
||||
}
|
||||
return targetType;
|
||||
}
|
||||
|
||||
/// Check for a generic type, and apply type arguments.
|
||||
FunctionType _instantiateFunctionType(
|
||||
FunctionType invokeType, TypeArgumentList typeArguments, AstNode node) {
|
||||
var typeFormals = invokeType.typeFormals;
|
||||
var arguments = typeArguments?.arguments;
|
||||
if (arguments != null && arguments.length != typeFormals.length) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
|
||||
node,
|
||||
[invokeType, typeFormals.length, arguments?.length ?? 0]);
|
||||
arguments = null;
|
||||
}
|
||||
|
||||
if (typeFormals.isNotEmpty) {
|
||||
if (arguments == null) {
|
||||
return _resolver.typeSystem.instantiateToBounds(invokeType);
|
||||
} else {
|
||||
return invokeType.instantiate(arguments.map((n) => n.type).toList());
|
||||
}
|
||||
}
|
||||
|
||||
return invokeType;
|
||||
}
|
||||
|
||||
bool _isCoreFunction(DartType type) {
|
||||
// TODO(scheglov) Can we optimize this?
|
||||
return type is InterfaceType && type.isDartCoreFunction;
|
||||
}
|
||||
|
||||
ExecutableElement _lookUpClassMember(ClassElement element, String name) {
|
||||
// TODO(scheglov) Use class hierarchy.
|
||||
return element.lookUpMethod(name, _definingLibrary);
|
||||
}
|
||||
|
||||
/// Return a signature of a member of a superinterface of [type].
|
||||
/// It might be abstract.
|
||||
/// TODO(scheglov) Replace this with class hierarchy.
|
||||
FunctionType _lookUpInheritedMember(InterfaceType type, Name name) {
|
||||
for (var mixin in type.mixins.reversed) {
|
||||
var result = _inheritance.getMember(mixin, name);
|
||||
if (result != null) return result;
|
||||
}
|
||||
{
|
||||
var result = _inheritance.getMember(type.superclass, name);
|
||||
if (result != null) return result;
|
||||
}
|
||||
for (var interface in type.interfaces) {
|
||||
var result = _inheritance.getMember(interface, name);
|
||||
if (result != null) return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _reportInvocationOfNonFunction(MethodInvocation node) {
|
||||
_setDynamicResolution(node, setNameTypeToDynamic: false);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION,
|
||||
node.methodName,
|
||||
[node.methodName.name],
|
||||
);
|
||||
}
|
||||
|
||||
void _reportPrefixIdentifierNotFollowedByDot(SimpleIdentifier target) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
|
||||
target,
|
||||
[target.name],
|
||||
);
|
||||
}
|
||||
|
||||
void _reportUndefinedFunction(
|
||||
MethodInvocation node, Identifier ignorableIdentifier) {
|
||||
_setDynamicResolution(node);
|
||||
|
||||
// TODO(scheglov) This is duplication.
|
||||
if (nameScope.shouldIgnoreUndefined(ignorableIdentifier)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.UNDEFINED_FUNCTION,
|
||||
node.methodName,
|
||||
[node.methodName.name],
|
||||
);
|
||||
}
|
||||
|
||||
void _reportUndefinedMethod(
|
||||
MethodInvocation node, String name, ClassElement typeReference) {
|
||||
_setDynamicResolution(node);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.UNDEFINED_METHOD,
|
||||
node.methodName,
|
||||
[name, typeReference.displayName],
|
||||
);
|
||||
}
|
||||
|
||||
void _reportUseOfVoidType(MethodInvocation node, AstNode errorNode) {
|
||||
_setDynamicResolution(node);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticWarningCode.USE_OF_VOID_RESULT,
|
||||
errorNode,
|
||||
);
|
||||
}
|
||||
|
||||
/// Given an [argumentList] and the [executableElement] that will be invoked
|
||||
/// using those argument, compute the list of parameters that correspond to the
|
||||
/// list of arguments. An error will be reported if any of the arguments cannot
|
||||
/// be matched to a parameter. The flag [reportAsError] should be `true` if a
|
||||
/// compile-time error should be reported; or `false` if a compile-time warning
|
||||
/// should be reported. Return the parameters that correspond to the arguments,
|
||||
/// or `null` if no correspondence could be computed.
|
||||
List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
|
||||
ArgumentList argumentList, ExecutableElement executableElement) {
|
||||
if (executableElement == null) {
|
||||
return null;
|
||||
}
|
||||
List<ParameterElement> parameters = executableElement.parameters;
|
||||
return _resolveArgumentsToParameters(
|
||||
reportAsError, argumentList, parameters);
|
||||
}
|
||||
|
||||
/// Given an [argumentList] and the [parameters] related to the element that
|
||||
/// will be invoked using those arguments, compute the list of parameters that
|
||||
/// correspond to the list of arguments. An error will be reported if any of
|
||||
/// the arguments cannot be matched to a parameter. The flag [reportAsError]
|
||||
/// should be `true` if a compile-time error should be reported; or `false` if
|
||||
/// a compile-time warning should be reported. Return the parameters that
|
||||
/// correspond to the arguments.
|
||||
List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
|
||||
ArgumentList argumentList, List<ParameterElement> parameters) {
|
||||
return ResolverVisitor.resolveArgumentsToParameters(
|
||||
argumentList, parameters, _resolver.errorReporter.reportErrorForNode,
|
||||
reportAsError: reportAsError);
|
||||
}
|
||||
|
||||
/// Given that we are accessing a property of the given [classElement] with the
|
||||
/// given [propertyName], return the element that represents the property.
|
||||
Element _resolveElement(
|
||||
ClassElement classElement, SimpleIdentifier propertyName) {
|
||||
// TODO(scheglov) Replace with class hierarchy.
|
||||
String name = propertyName.name;
|
||||
Element element = null;
|
||||
if (propertyName.inSetterContext()) {
|
||||
element = classElement.getSetter(name);
|
||||
}
|
||||
if (element == null) {
|
||||
element = classElement.getGetter(name);
|
||||
}
|
||||
if (element == null) {
|
||||
element = classElement.getMethod(name);
|
||||
}
|
||||
if (element != null && element.isAccessibleIn(_definingLibrary)) {
|
||||
return element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _resolveReceiverDynamic(MethodInvocation node, String name) {
|
||||
_setDynamicResolution(node);
|
||||
}
|
||||
|
||||
void _resolveReceiverFunctionType(MethodInvocation node, Expression receiver,
|
||||
FunctionType receiverType, SimpleIdentifier nameNode, String name) {
|
||||
if (name == FunctionElement.CALL_METHOD_NAME) {
|
||||
_setResolution(node, receiverType);
|
||||
// TODO(scheglov) Replace this with using FunctionType directly.
|
||||
// Here was erase resolution that _setResolution() sets.
|
||||
nameNode.staticElement = null;
|
||||
nameNode.staticType = _dynamicType;
|
||||
return;
|
||||
}
|
||||
|
||||
// We can invoke Object methods on Function.
|
||||
var type = _inheritance.getMember(
|
||||
_resolver.typeProvider.objectType,
|
||||
new Name(null, name),
|
||||
);
|
||||
if (type != null) {
|
||||
nameNode.staticElement = type.element;
|
||||
return _setResolution(node, type);
|
||||
}
|
||||
|
||||
_reportUndefinedMethod(
|
||||
node,
|
||||
name,
|
||||
_resolver.typeProvider.functionType.element,
|
||||
);
|
||||
}
|
||||
|
||||
void _resolveReceiverInterfaceType(MethodInvocation node,
|
||||
InterfaceType receiverType, SimpleIdentifier nameNode, String name) {
|
||||
if (_isCoreFunction(receiverType) &&
|
||||
name == FunctionElement.CALL_METHOD_NAME) {
|
||||
_setDynamicResolution(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(scheglov) It is wasteful: get library URI multiple times.
|
||||
// TODO(scheglov) It is wasteful: create names multiple times.
|
||||
var targetType = _inheritance.getMember(
|
||||
receiverType,
|
||||
new Name(_definingLibrary.source.uri, name),
|
||||
);
|
||||
if (targetType != null) {
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
|
||||
// TODO(scheglov) This is bad, we have to create members here.
|
||||
// Find a way to avoid this.
|
||||
Element element;
|
||||
var baseElement = targetType.element;
|
||||
if (baseElement is MethodElement) {
|
||||
element = MethodMember.from(baseElement, receiverType);
|
||||
} else if (baseElement is PropertyAccessorElement) {
|
||||
element = PropertyAccessorMember.from(baseElement, receiverType);
|
||||
}
|
||||
nameNode.staticElement = element;
|
||||
|
||||
return _setResolution(node, calleeType);
|
||||
}
|
||||
|
||||
// The interface of the receiver does not have an instance member.
|
||||
// Try to recover and find a member in the class.
|
||||
var targetElement = _lookUpClassMember(receiverType.element, name);
|
||||
if (targetElement != null && targetElement.isStatic) {
|
||||
nameNode.staticElement = targetElement;
|
||||
_setDynamicResolution(node);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
|
||||
nameNode,
|
||||
[
|
||||
name,
|
||||
targetElement.kind.displayName,
|
||||
targetElement.enclosingElement.displayName,
|
||||
],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_setDynamicResolution(node);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.UNDEFINED_METHOD,
|
||||
nameNode,
|
||||
[name, receiverType.element.displayName],
|
||||
);
|
||||
}
|
||||
|
||||
void _resolveReceiverNull(
|
||||
MethodInvocation node, SimpleIdentifier nameNode, String name) {
|
||||
var element = nameScope.lookup(nameNode, _definingLibrary);
|
||||
if (element != null) {
|
||||
nameNode.staticElement = element;
|
||||
if (element is MultiplyDefinedElement) {
|
||||
MultiplyDefinedElement multiply = element;
|
||||
element = multiply.conflictingElements[0];
|
||||
}
|
||||
if (element is ExecutableElement) {
|
||||
var calleeType = _getCalleeType(element.type);
|
||||
return _setResolution(node, calleeType);
|
||||
}
|
||||
if (element is VariableElement) {
|
||||
var targetType = _promoteManager.getStaticType(element);
|
||||
return _setResolution(node, targetType);
|
||||
}
|
||||
// TODO(scheglov) This is a questionable distinction.
|
||||
if (element is PrefixElement) {
|
||||
_setDynamicResolution(node);
|
||||
return _reportPrefixIdentifierNotFollowedByDot(nameNode);
|
||||
}
|
||||
return _reportInvocationOfNonFunction(node);
|
||||
}
|
||||
|
||||
ClassElement enclosingClass = _resolver.enclosingClass;
|
||||
if (enclosingClass == null) {
|
||||
return _reportUndefinedFunction(node, node.methodName);
|
||||
}
|
||||
|
||||
var receiverType = enclosingClass.type;
|
||||
var targetType = _inheritance.getMember(
|
||||
receiverType,
|
||||
new Name(_definingLibrary.source.uri, name),
|
||||
);
|
||||
|
||||
if (targetType != null) {
|
||||
nameNode.staticElement = targetType.element;
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
return _setResolution(node, calleeType);
|
||||
}
|
||||
|
||||
var targetElement = _lookUpClassMember(enclosingClass, name);
|
||||
if (targetElement != null && targetElement.isStatic) {
|
||||
nameNode.staticElement = targetElement;
|
||||
_setDynamicResolution(node);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
|
||||
nameNode,
|
||||
[receiverType.displayName],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return _reportUndefinedMethod(node, name, enclosingClass);
|
||||
}
|
||||
|
||||
void _resolveReceiverPrefix(MethodInvocation node, SimpleIdentifier receiver,
|
||||
PrefixElement prefix, SimpleIdentifier nameNode, String name) {
|
||||
if (node.operator.type == TokenType.QUESTION_PERIOD) {
|
||||
_reportPrefixIdentifierNotFollowedByDot(receiver);
|
||||
}
|
||||
|
||||
if (name == FunctionElement.LOAD_LIBRARY_NAME) {
|
||||
var imports = _definingLibrary.getImportsWithPrefix(prefix);
|
||||
if (imports.length == 1 && imports[0].isDeferred) {
|
||||
var importedLibrary = imports[0].importedLibrary;
|
||||
var loadLibraryFunction = importedLibrary?.loadLibraryFunction;
|
||||
nameNode.staticElement = loadLibraryFunction;
|
||||
node.staticInvokeType = loadLibraryFunction?.type;
|
||||
node.staticType = loadLibraryFunction?.returnType;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(scheglov) I don't like how we resolve prefixed names.
|
||||
// But maybe this is the only one solution.
|
||||
var prefixedName = new PrefixedIdentifierImpl.temp(receiver, nameNode);
|
||||
var element = nameScope.lookup(prefixedName, _definingLibrary);
|
||||
nameNode.staticElement = element;
|
||||
|
||||
if (element is MultiplyDefinedElement) {
|
||||
MultiplyDefinedElement multiply = element;
|
||||
element = multiply.conflictingElements[0];
|
||||
}
|
||||
|
||||
if (element is ExecutableElement) {
|
||||
var calleeType = _getCalleeType(element.type);
|
||||
return _setResolution(node, calleeType);
|
||||
}
|
||||
|
||||
_reportUndefinedFunction(node, prefixedName);
|
||||
}
|
||||
|
||||
void _resolveReceiverSuper(MethodInvocation node, SuperExpression receiver,
|
||||
SimpleIdentifier nameNode, String name) {
|
||||
if (!_isSuperInValidContext(receiver)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var receiverType = _resolver.enclosingClass.type;
|
||||
var targetType = _inheritance.getMember(
|
||||
receiverType,
|
||||
new Name(_definingLibrary.source.uri, name),
|
||||
forSuper: true,
|
||||
);
|
||||
|
||||
// If there is that concrete dispatch target, then we are done.
|
||||
if (targetType != null) {
|
||||
nameNode.staticElement = targetType.element;
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
_setResolution(node, calleeType);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, this is an error.
|
||||
// But we would like to give the user at least some resolution.
|
||||
// So, we try to find the interface target.
|
||||
targetType = _lookUpInheritedMember(
|
||||
receiverType,
|
||||
new Name(_definingLibrary.source.uri, name),
|
||||
);
|
||||
if (targetType != null) {
|
||||
nameNode.staticElement = targetType.element;
|
||||
var calleeType = _getCalleeType(targetType);
|
||||
_setResolution(node, calleeType);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
|
||||
nameNode,
|
||||
[targetType.element.kind.displayName, name]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Nothing help, there is no target at all.
|
||||
_setDynamicResolution(node);
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.UNDEFINED_SUPER_METHOD,
|
||||
nameNode,
|
||||
[name, _resolver.enclosingClass.displayName]);
|
||||
}
|
||||
|
||||
void _resolveReceiverTypeLiteral(MethodInvocation node, ClassElement receiver,
|
||||
SimpleIdentifier nameNode, String name) {
|
||||
if (node.isCascaded) {
|
||||
receiver = _typeType.element;
|
||||
}
|
||||
|
||||
var element = _resolveElement(receiver, nameNode);
|
||||
if (element != null) {
|
||||
if (element is ExecutableElement) {
|
||||
nameNode.staticElement = element;
|
||||
var calleeType = _getCalleeType(element.type);
|
||||
_setResolution(node, calleeType);
|
||||
} else {
|
||||
_reportInvocationOfNonFunction(node);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_reportUndefinedMethod(node, name, receiver);
|
||||
}
|
||||
|
||||
/// If the given [type] is a type parameter, replace with its bound.
|
||||
/// Otherwise, return the original type.
|
||||
DartType _resolveTypeParameter(DartType type) {
|
||||
if (type is TypeParameterType) {
|
||||
return type.resolveToBound(_resolver.typeProvider.objectType);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
void _setDynamicResolution(MethodInvocation node,
|
||||
{bool setNameTypeToDynamic: true}) {
|
||||
if (setNameTypeToDynamic) {
|
||||
node.methodName.staticType = _dynamicType;
|
||||
}
|
||||
node.staticInvokeType = _dynamicType;
|
||||
node.staticType = _dynamicType;
|
||||
}
|
||||
|
||||
void _setResolution(MethodInvocation node, DartType type) {
|
||||
if (type == _dynamicType || _isCoreFunction(type)) {
|
||||
_setDynamicResolution(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(scheglov) We need this for StaticTypeAnalyzer to run inference.
|
||||
// But it seems weird. Do we need to know the raw type of a function?!
|
||||
node.methodName.staticType = type;
|
||||
|
||||
if (type is InterfaceType) {
|
||||
var call = _inheritance.getMember(type, _nameCall);
|
||||
if (call != null && call.element.kind == ElementKind.METHOD) {
|
||||
type = call;
|
||||
}
|
||||
}
|
||||
|
||||
if (type is FunctionType) {
|
||||
// TODO(scheglov) Extract this when receiver is already FunctionType?
|
||||
var instantiatedType = _instantiateFunctionType(
|
||||
type,
|
||||
node.typeArguments,
|
||||
node.methodName,
|
||||
);
|
||||
node.staticInvokeType = instantiatedType;
|
||||
node.staticType = instantiatedType.returnType;
|
||||
// TODO(scheglov) too much magic
|
||||
node.argumentList.correspondingStaticParameters =
|
||||
_computeCorrespondingParameters(
|
||||
node.argumentList,
|
||||
instantiatedType,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type is VoidType) {
|
||||
return _reportUseOfVoidType(node, node.methodName);
|
||||
}
|
||||
|
||||
_reportInvocationOfNonFunction(node);
|
||||
}
|
||||
|
||||
/// Checks whether the given [expression] is a reference to a class. If it is
|
||||
/// then the element representing the class is returned, otherwise `null` is
|
||||
/// returned.
|
||||
static ClassElement getTypeReference(Expression expression) {
|
||||
if (expression is Identifier) {
|
||||
Element staticElement = expression.staticElement;
|
||||
if (staticElement is ClassElement) {
|
||||
return staticElement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Return `true` if the given 'super' [expression] is used in a valid context.
|
||||
static bool _isSuperInValidContext(SuperExpression expression) {
|
||||
for (AstNode node = expression; node != null; node = node.parent) {
|
||||
if (node is CompilationUnit) {
|
||||
return false;
|
||||
} else if (node is ConstructorDeclaration) {
|
||||
return node.factoryKeyword == null;
|
||||
} else if (node is ConstructorFieldInitializer) {
|
||||
return false;
|
||||
} else if (node is MethodDeclaration) {
|
||||
return !node.isStatic;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import 'package:analyzer/src/dart/ast/token.dart';
|
|||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
import 'package:analyzer/src/generated/resolver.dart';
|
||||
|
@ -108,24 +109,21 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
*/
|
||||
InterfaceType _typeType;
|
||||
|
||||
/**
|
||||
* The object keeping track of which elements have had their types promoted.
|
||||
*/
|
||||
TypePromotionManager _promoteManager;
|
||||
|
||||
/// Whether constant evaluation errors should be reported during resolution.
|
||||
final bool reportConstEvaluationErrors;
|
||||
|
||||
final MethodInvocationResolver _methodInvocationResolver;
|
||||
|
||||
/**
|
||||
* Initialize a newly created visitor to work for the given [_resolver] to
|
||||
* resolve the nodes in a compilation unit.
|
||||
*/
|
||||
ElementResolver(this._resolver, {this.reportConstEvaluationErrors: true})
|
||||
: _inheritance = _resolver.inheritance,
|
||||
_definingLibrary = _resolver.definingLibrary {
|
||||
_definingLibrary = _resolver.definingLibrary,
|
||||
_methodInvocationResolver = new MethodInvocationResolver(_resolver) {
|
||||
_dynamicType = _resolver.typeProvider.dynamicType;
|
||||
_typeType = _resolver.typeProvider.typeType;
|
||||
_promoteManager = _resolver.promoteManager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -537,212 +535,7 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
|
||||
@override
|
||||
Object visitMethodInvocation(MethodInvocation node) {
|
||||
SimpleIdentifier methodName = node.methodName;
|
||||
//
|
||||
// Synthetic identifiers have been already reported during parsing.
|
||||
//
|
||||
if (methodName.isSynthetic) {
|
||||
return null;
|
||||
}
|
||||
//
|
||||
// We have a method invocation of one of two forms: 'e.m(a1, ..., an)' or
|
||||
// 'm(a1, ..., an)'. The first step is to figure out which executable is
|
||||
// being invoked, using both the static and the propagated type information.
|
||||
//
|
||||
Expression target = node.realTarget;
|
||||
if (target is SuperExpression && !_isSuperInValidContext(target)) {
|
||||
return null;
|
||||
}
|
||||
Element staticElement;
|
||||
if (target == null) {
|
||||
staticElement = _resolveInvokedElement(methodName);
|
||||
} else if (methodName.name == FunctionElement.LOAD_LIBRARY_NAME &&
|
||||
_isDeferredPrefix(target)) {
|
||||
if (node.operator.type == TokenType.QUESTION_PERIOD) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
|
||||
target,
|
||||
[(target as SimpleIdentifier).name]);
|
||||
}
|
||||
LibraryElement importedLibrary = _getImportedLibrary(target);
|
||||
FunctionElement loadLibraryFunction =
|
||||
importedLibrary?.loadLibraryFunction;
|
||||
methodName.staticElement = loadLibraryFunction;
|
||||
node.staticInvokeType = loadLibraryFunction?.type;
|
||||
return null;
|
||||
} else {
|
||||
//
|
||||
// If this method invocation is of the form 'C.m' where 'C' is a class,
|
||||
// then we don't call resolveInvokedElement(...) which walks up the class
|
||||
// hierarchy, instead we just look for the member in the type only. This
|
||||
// does not apply to conditional method invocation (i.e. 'C?.m(...)').
|
||||
//
|
||||
bool isConditional = node.operator.type == TokenType.QUESTION_PERIOD;
|
||||
ClassElement typeReference = getTypeReference(target);
|
||||
|
||||
if (typeReference != null) {
|
||||
if (node.isCascaded) {
|
||||
typeReference = _typeType.element;
|
||||
}
|
||||
staticElement = _resolveElement(typeReference, methodName);
|
||||
} else {
|
||||
DartType staticType = _getStaticTypeOrFunctionType(target);
|
||||
|
||||
if (staticType is FunctionType &&
|
||||
methodName.name == FunctionElement.CALL_METHOD_NAME) {
|
||||
if (target is SimpleIdentifier) {
|
||||
methodName.staticElement = target.staticElement;
|
||||
}
|
||||
methodName.staticType = target.staticType;
|
||||
node.staticType = staticType;
|
||||
node.staticInvokeType = staticType;
|
||||
node.argumentList.correspondingStaticParameters =
|
||||
_computeCorrespondingParameters(node.argumentList, staticType);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (target is SuperExpression) {
|
||||
if (staticType is InterfaceTypeImpl) {
|
||||
staticElement = staticType.lookUpInheritedMember(
|
||||
methodName.name, _definingLibrary,
|
||||
concrete: true, forSuperInvocation: true);
|
||||
// We were not able to find the concrete dispatch target.
|
||||
// But we would like to give the user at least some resolution.
|
||||
// So, we retry without the "concrete" requirement.
|
||||
if (staticElement == null) {
|
||||
staticElement = staticType.lookUpInheritedMember(
|
||||
methodName.name, _definingLibrary,
|
||||
concrete: false);
|
||||
if (staticElement != null) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
|
||||
methodName,
|
||||
[staticElement.kind.displayName, methodName.name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
staticElement = _resolveInvokedElementWithTarget(
|
||||
target, staticType, methodName, isConditional);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
staticElement = _convertSetterToGetter(staticElement);
|
||||
|
||||
//
|
||||
// Given the elements, determine the type of the function we are invoking
|
||||
//
|
||||
DartType staticType = _getInvokeType(staticElement);
|
||||
methodName.staticType = staticType;
|
||||
|
||||
//
|
||||
// Instantiate generic function or method if needed.
|
||||
//
|
||||
DartType staticInvokeType = _instantiateGenericMethod(
|
||||
staticType, node.typeArguments, node.methodName);
|
||||
|
||||
//
|
||||
// Record the results.
|
||||
//
|
||||
methodName.staticElement = staticElement;
|
||||
node.staticInvokeType = staticInvokeType;
|
||||
ArgumentList argumentList = node.argumentList;
|
||||
if (staticInvokeType != null) {
|
||||
List<ParameterElement> parameters =
|
||||
_computeCorrespondingParameters(argumentList, staticInvokeType);
|
||||
argumentList.correspondingStaticParameters = parameters;
|
||||
}
|
||||
//
|
||||
// Then check for error conditions.
|
||||
//
|
||||
ErrorCode errorCode = _checkForInvocationError(
|
||||
target, true, staticElement, staticType, methodName.name);
|
||||
if (errorCode != null &&
|
||||
target is SimpleIdentifier &&
|
||||
target.staticElement is PrefixElement) {
|
||||
Identifier functionName =
|
||||
new PrefixedIdentifierImpl.temp(target, methodName);
|
||||
if (_resolver.nameScope.shouldIgnoreUndefined(functionName)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (errorCode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (identical(
|
||||
errorCode, StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT) ||
|
||||
identical(errorCode, StaticTypeWarningCode.UNDEFINED_FUNCTION)) {
|
||||
if (!_resolver.nameScope.shouldIgnoreUndefined(methodName)) {
|
||||
_resolver.errorReporter
|
||||
.reportErrorForNode(errorCode, methodName, [methodName.name]);
|
||||
}
|
||||
} else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
|
||||
String targetTypeName;
|
||||
if (target == null) {
|
||||
ClassElement enclosingClass = _resolver.enclosingClass;
|
||||
targetTypeName = enclosingClass.displayName;
|
||||
ErrorCode proxyErrorCode = StaticTypeWarningCode.UNDEFINED_METHOD;
|
||||
_recordUndefinedNode(_resolver.enclosingClass, proxyErrorCode,
|
||||
methodName, [methodName.name, targetTypeName]);
|
||||
} else {
|
||||
// ignore Function "call"
|
||||
// (if we are about to create a hint using type propagation,
|
||||
// then we can use type propagation here as well)
|
||||
DartType targetType = null;
|
||||
targetType = _getStaticType(target);
|
||||
if (targetType != null &&
|
||||
targetType.isDartCoreFunction &&
|
||||
methodName.name == FunctionElement.CALL_METHOD_NAME) {
|
||||
return null;
|
||||
}
|
||||
if (!node.isCascaded) {
|
||||
ClassElement typeReference = getTypeReference(target);
|
||||
if (typeReference != null) {
|
||||
ConstructorElement constructor =
|
||||
typeReference.getNamedConstructor(methodName.name);
|
||||
if (constructor != null) {
|
||||
_recordUndefinedNode(
|
||||
typeReference,
|
||||
StaticTypeWarningCode.UNDEFINED_METHOD_WITH_CONSTRUCTOR,
|
||||
methodName,
|
||||
[methodName.name, typeReference.name]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
targetTypeName = targetType?.displayName;
|
||||
ErrorCode proxyErrorCode = StaticTypeWarningCode.UNDEFINED_METHOD;
|
||||
|
||||
_recordUndefinedNode(targetType.element, proxyErrorCode, methodName,
|
||||
[methodName.name, targetTypeName]);
|
||||
}
|
||||
} else if (identical(
|
||||
errorCode, StaticTypeWarningCode.UNDEFINED_SUPER_METHOD)) {
|
||||
// Generate the type name.
|
||||
// The error code will never be generated via type propagation
|
||||
DartType getSuperType(DartType type) {
|
||||
if (type is InterfaceType) {
|
||||
InterfaceType superclass = type.superclass;
|
||||
if (superclass != null) return superclass;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
DartType targetType = getSuperType(_getStaticType(target));
|
||||
String targetTypeName = targetType?.name;
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticTypeWarningCode.UNDEFINED_SUPER_METHOD,
|
||||
methodName,
|
||||
[methodName.name, targetTypeName]);
|
||||
} else if (identical(errorCode, StaticWarningCode.USE_OF_VOID_RESULT)) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
StaticWarningCode.USE_OF_VOID_RESULT, target ?? methodName, []);
|
||||
}
|
||||
_methodInvocationResolver.resolve(node);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1121,99 +914,6 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given that we have found code to invoke the given [element], return the
|
||||
* error code that should be reported, or `null` if no error should be
|
||||
* reported. The [target] is the target of the invocation, or `null` if there
|
||||
* was no target. The flag [useStaticContext] should be `true` if the
|
||||
* invocation is in a static constant (does not have access to instance state).
|
||||
*/
|
||||
ErrorCode _checkForInvocationError(Expression target, bool useStaticContext,
|
||||
Element element, DartType type, String name) {
|
||||
// Prefix is not declared, instead "prefix.id" are declared.
|
||||
if (element is PrefixElement) {
|
||||
return CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT;
|
||||
} else if (element is PropertyAccessorElement) {
|
||||
//
|
||||
// This is really a function expression invocation.
|
||||
//
|
||||
// TODO(brianwilkerson) Consider the possibility of re-writing the AST.
|
||||
FunctionType getterType = element.type;
|
||||
if (getterType != null) {
|
||||
DartType returnType = getterType.returnType;
|
||||
return _getErrorCodeForExecuting(returnType);
|
||||
}
|
||||
} else if (element is ExecutableElement) {
|
||||
return null;
|
||||
} else if (element is MultiplyDefinedElement) {
|
||||
// The error has already been reported
|
||||
return null;
|
||||
} else if (element == null && target is SuperExpression) {
|
||||
// TODO(jwren) We should split the UNDEFINED_METHOD into two error codes,
|
||||
// this one, and a code that describes the situation where the method was
|
||||
// found, but it was not accessible from the current library.
|
||||
return StaticTypeWarningCode.UNDEFINED_SUPER_METHOD;
|
||||
} else {
|
||||
//
|
||||
// This is really a function expression invocation.
|
||||
//
|
||||
// TODO(brianwilkerson) Consider the possibility of re-writing the AST.
|
||||
if (element is PropertyInducingElement) {
|
||||
PropertyAccessorElement getter = element.getter;
|
||||
FunctionType getterType = getter.type;
|
||||
if (getterType != null) {
|
||||
DartType returnType = getterType.returnType;
|
||||
return _getErrorCodeForExecuting(returnType);
|
||||
}
|
||||
} else if (element is VariableElement) {
|
||||
return _getErrorCodeForExecuting(type);
|
||||
} else {
|
||||
if (target == null) {
|
||||
ClassElement enclosingClass = _resolver.enclosingClass;
|
||||
if (enclosingClass == null) {
|
||||
return StaticTypeWarningCode.UNDEFINED_FUNCTION;
|
||||
} else if (element == null) {
|
||||
// Proxy-conditional warning, based on state of
|
||||
// resolver.getEnclosingClass()
|
||||
return StaticTypeWarningCode.UNDEFINED_METHOD;
|
||||
} else {
|
||||
return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
|
||||
}
|
||||
} else {
|
||||
DartType targetType;
|
||||
if (useStaticContext) {
|
||||
targetType = _getStaticType(target);
|
||||
} else {
|
||||
// Compute and use the propagated type, if it is null, then it may
|
||||
// be the case that static type is some type, in which the static
|
||||
// type should be used.
|
||||
targetType = _getBestType(target);
|
||||
}
|
||||
if (targetType == null) {
|
||||
if (target is Identifier &&
|
||||
_resolver.nameScope.shouldIgnoreUndefined(target)) {
|
||||
return null;
|
||||
}
|
||||
return StaticTypeWarningCode.UNDEFINED_FUNCTION;
|
||||
} else if (targetType.isVoid) {
|
||||
return StaticWarningCode.USE_OF_VOID_RESULT;
|
||||
} else if (!targetType.isDynamic && target is! NullLiteral) {
|
||||
// Proxy-conditional warning, based on state of
|
||||
// targetType.getElement()
|
||||
return StaticTypeWarningCode.UNDEFINED_METHOD;
|
||||
} else if (targetType.isDynamic) {
|
||||
PropertyAccessorElement getter =
|
||||
_resolver.typeProvider.objectType.getGetter(name);
|
||||
if (getter != null && getter.returnType is! FunctionType) {
|
||||
return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the given index [expression] was resolved, otherwise a
|
||||
* [StaticTypeWarningCode.UNDEFINED_OPERATOR] is generated. The [target] is
|
||||
|
@ -1274,50 +974,6 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given [element] is a setter, return the getter associated with it.
|
||||
* Otherwise, return the element unchanged.
|
||||
*/
|
||||
Element _convertSetterToGetter(Element element) {
|
||||
// TODO(brianwilkerson) Determine whether and why the element could ever be
|
||||
// a setter.
|
||||
if (element is PropertyAccessorElement) {
|
||||
return element.variable.getter;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the best type of the given [expression] that is to be used for
|
||||
* type analysis.
|
||||
*/
|
||||
DartType _getBestType(Expression expression) {
|
||||
DartType bestType = _resolveTypeParameter(expression.staticType);
|
||||
if (bestType is FunctionType) {
|
||||
//
|
||||
// All function types are subtypes of 'Function', which is itself a
|
||||
// subclass of 'Object'.
|
||||
//
|
||||
bestType = _resolver.typeProvider.functionType;
|
||||
}
|
||||
return bestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error if the [type], which is presumably being invoked, is not a
|
||||
* function. The errors for non functions may be broken up by type; currently,
|
||||
* it returns a special value for when the type is `void`.
|
||||
*/
|
||||
ErrorCode _getErrorCodeForExecuting(DartType type) {
|
||||
if (_isExecutableType(type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return type.isVoid
|
||||
? StaticWarningCode.USE_OF_VOID_RESULT
|
||||
: StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming that the given [identifier] is a prefix for a deferred import,
|
||||
* return the library that is being imported.
|
||||
|
@ -1329,28 +985,6 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
return imports[0].importedLibrary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an element, computes the type of the invocation.
|
||||
*
|
||||
* For executable elements (like methods, functions) this is just their type.
|
||||
*
|
||||
* For variables it is their type taking into account any type promotion.
|
||||
*
|
||||
* For calls to getters in Dart, we invoke the function that is returned by
|
||||
* the getter, so the invoke type is the getter's returnType.
|
||||
*/
|
||||
DartType _getInvokeType(Element element) {
|
||||
DartType invokeType;
|
||||
if (element is PropertyAccessorElement) {
|
||||
invokeType = element.returnType;
|
||||
} else if (element is ExecutableElement) {
|
||||
invokeType = element.type;
|
||||
} else if (element is VariableElement) {
|
||||
invokeType = _promoteManager.getStaticType(element);
|
||||
}
|
||||
return invokeType ?? DynamicTypeImpl.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the method invoked by the given postfix [expression].
|
||||
*/
|
||||
|
@ -1460,25 +1094,6 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if the given [type] represents an object that could be
|
||||
* invoked using the call operator '()'.
|
||||
*/
|
||||
bool _isExecutableType(DartType type) {
|
||||
type = type?.resolveToBound(_resolver.typeProvider.objectType);
|
||||
if (type.isDynamic || type is FunctionType) {
|
||||
return true;
|
||||
} else if (type.isDartCoreFunction) {
|
||||
return true;
|
||||
} else if (type is InterfaceType) {
|
||||
ClassElement classElement = type.element;
|
||||
MethodElement methodElement = classElement.lookUpMethod(
|
||||
FunctionElement.CALL_METHOD_NAME, _definingLibrary);
|
||||
return methodElement != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if the given [element] is a static element.
|
||||
*/
|
||||
|
@ -1582,18 +1197,18 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
|
||||
/**
|
||||
* Look up the [FunctionType] of a getter or a method with the given [name]
|
||||
* in the given [targetType]. The [target] is the target of the invocation,
|
||||
* or `null` if there is no target.
|
||||
* in the given [targetType].
|
||||
*/
|
||||
FunctionType _lookUpGetterType(
|
||||
Expression target, DartType targetType, String name) {
|
||||
FunctionType _lookUpGetterType(DartType targetType, String name,
|
||||
{bool concrete: false, bool forSuper: false}) {
|
||||
targetType = _resolveTypeParameter(targetType);
|
||||
if (targetType is InterfaceType) {
|
||||
var nameObject = new Name(_definingLibrary.source.uri, name);
|
||||
return _inheritance.getMember(
|
||||
targetType,
|
||||
nameObject,
|
||||
forSuper: target is SuperExpression,
|
||||
concrete: concrete,
|
||||
forSuper: forSuper,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
@ -1894,12 +1509,14 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
Expression leftOperand = node.leftOperand;
|
||||
if (leftOperand != null) {
|
||||
DartType leftType = _getStaticType(leftOperand);
|
||||
var invokeType = _lookUpGetterType(leftOperand, leftType, methodName);
|
||||
var isSuper = leftOperand is SuperExpression;
|
||||
var invokeType = _lookUpGetterType(leftType, methodName,
|
||||
concrete: isSuper, forSuper: isSuper);
|
||||
var invokeElement = invokeType?.element;
|
||||
node.staticElement = invokeElement;
|
||||
node.staticInvokeType = invokeType;
|
||||
if (_shouldReportMissingMember(leftType, invokeElement)) {
|
||||
if (leftOperand is SuperExpression) {
|
||||
if (isSuper) {
|
||||
_recordUndefinedToken(
|
||||
leftType.element,
|
||||
StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR,
|
||||
|
@ -1977,103 +1594,6 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the
|
||||
* element being invoked. If the returned element is a method, then the method
|
||||
* will be invoked. If the returned element is a getter, the getter will be
|
||||
* invoked without arguments and the result of that invocation will then be
|
||||
* invoked with the arguments. The [methodName] is the name of the method
|
||||
* being invoked ('m').
|
||||
*/
|
||||
Element _resolveInvokedElement(SimpleIdentifier methodName) {
|
||||
//
|
||||
// Look first in the lexical scope.
|
||||
//
|
||||
Element element = _resolver.nameScope.lookup(methodName, _definingLibrary);
|
||||
if (element == null) {
|
||||
//
|
||||
// If it isn't defined in the lexical scope, and the invocation is within
|
||||
// a class, then look in the inheritance scope.
|
||||
//
|
||||
ClassElement enclosingClass = _resolver.enclosingClass;
|
||||
if (enclosingClass != null) {
|
||||
InterfaceType enclosingType = enclosingClass.type;
|
||||
element = _lookUpMethod(null, enclosingType, methodName.name);
|
||||
if (element == null) {
|
||||
//
|
||||
// If there's no method, then it's possible that 'm' is a getter that
|
||||
// returns a function.
|
||||
//
|
||||
element = _lookUpGetter(null, enclosingType, methodName.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(brianwilkerson) Report this error.
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the
|
||||
* element being invoked. If the returned element is a method, then the method
|
||||
* will be invoked. If the returned element is a getter, the getter will be
|
||||
* invoked without arguments and the result of that invocation will then be
|
||||
* invoked with the arguments. The [target] is the target of the invocation
|
||||
* ('e'). The [targetType] is the type of the target. The [methodName] is th
|
||||
* name of the method being invoked ('m'). [isConditional] indicates
|
||||
* whether the invocation uses a '?.' operator.
|
||||
*/
|
||||
Element _resolveInvokedElementWithTarget(Expression target,
|
||||
DartType targetType, SimpleIdentifier methodName, bool isConditional) {
|
||||
String name = methodName.name;
|
||||
if (targetType is InterfaceType) {
|
||||
Element element = _lookUpMethod(target, targetType, name);
|
||||
if (element == null) {
|
||||
//
|
||||
// If there's no method, then it's possible that 'm' is a getter that
|
||||
// returns a function.
|
||||
//
|
||||
// TODO (collinsn): need to add union type support here too, in the
|
||||
// style of [lookUpMethod].
|
||||
element = _lookUpGetter(target, targetType, name);
|
||||
}
|
||||
return element;
|
||||
} else if (targetType is FunctionType &&
|
||||
_resolver.typeProvider.isObjectMethod(name)) {
|
||||
return _resolver.typeProvider.objectType.element.getMethod(name);
|
||||
} else if (target is SimpleIdentifier) {
|
||||
Element targetElement = target.staticElement;
|
||||
if (targetType is FunctionType &&
|
||||
name == FunctionElement.CALL_METHOD_NAME) {
|
||||
return targetElement;
|
||||
}
|
||||
if (targetElement is PrefixElement) {
|
||||
if (isConditional) {
|
||||
_resolver.errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
|
||||
target,
|
||||
[target.name]);
|
||||
}
|
||||
//
|
||||
// Look to see whether the name of the method is really part of a
|
||||
// prefixed identifier for an imported top-level function or top-level
|
||||
// getter that returns a function.
|
||||
//
|
||||
Identifier functionName =
|
||||
new PrefixedIdentifierImpl.temp(target, methodName);
|
||||
Element element =
|
||||
_resolver.nameScope.lookup(functionName, _definingLibrary);
|
||||
if (element != null) {
|
||||
// TODO(brianwilkerson) This isn't a method invocation, it's a
|
||||
// function invocation where the function name is a prefixed
|
||||
// identifier. Consider re-writing the AST.
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(brianwilkerson) Report this error.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a [node] that can have annotations associated with it, resolve the
|
||||
* annotations in the element model representing annotations to the node.
|
||||
|
|
|
@ -4154,7 +4154,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
|||
|
||||
var superMemberType = _inheritanceManager.getMember(
|
||||
enclosingType, nameObject,
|
||||
forMixinIndex: mixinIndex, forSuper: true);
|
||||
forMixinIndex: mixinIndex, concrete: true, forSuper: true);
|
||||
|
||||
if (superMemberType == null) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
|
|
|
@ -517,7 +517,9 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
visitMethodInvocation(MethodInvocation node) {
|
||||
var target = node.realTarget;
|
||||
var element = node.methodName.staticElement;
|
||||
if (element == null && !typeProvider.isObjectMethod(node.methodName.name)) {
|
||||
if (element == null &&
|
||||
!typeProvider.isObjectMethod(node.methodName.name) &&
|
||||
node.methodName.name != FunctionElement.CALL_METHOD_NAME) {
|
||||
_recordDynamicInvoke(node, target);
|
||||
|
||||
// Mark the tear-off as being dynamic, too. This lets us distinguish
|
||||
|
|
|
@ -5214,23 +5214,6 @@ f() {
|
|||
verify([source]);
|
||||
}
|
||||
|
||||
test_prefix_conditionalPropertyAccess_call() async {
|
||||
addNamedSource('/lib.dart', '''
|
||||
library lib;
|
||||
g() {}
|
||||
''');
|
||||
Source source = addSource('''
|
||||
import 'lib.dart' as p;
|
||||
f() {
|
||||
p?.g();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(
|
||||
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_prefix_conditionalPropertyAccess_call_loadLibrary() async {
|
||||
addNamedSource('/lib.dart', '''
|
||||
library lib;
|
||||
|
@ -5313,36 +5296,6 @@ f() {
|
|||
verify([source]);
|
||||
}
|
||||
|
||||
test_prefix_unqualified_invocation_in_method() async {
|
||||
addNamedSource('/lib.dart', 'librarylib;');
|
||||
Source source = addSource('''
|
||||
import 'lib.dart' as p;
|
||||
class C {
|
||||
f() {
|
||||
p();
|
||||
}
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(
|
||||
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_prefix_unqualified_invocation_not_in_method() async {
|
||||
addNamedSource('/lib.dart', 'librarylib;');
|
||||
Source source = addSource('''
|
||||
import 'lib.dart' as p;
|
||||
f() {
|
||||
p();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(
|
||||
source, [CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT]);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_prefixCollidesWithTopLevelMembers_functionTypeAlias() async {
|
||||
addNamedSource("/lib.dart", r'''
|
||||
library lib;
|
||||
|
|
|
@ -829,31 +829,6 @@ class ElementResolverTest extends EngineTestCase with ResourceProviderMixin {
|
|||
_listener.assertNoErrors();
|
||||
}
|
||||
|
||||
test_visitMethodInvocation_namedParameter() async {
|
||||
ClassElementImpl classA = ElementFactory.classElement2("A");
|
||||
String methodName = "m";
|
||||
String parameterName = "p";
|
||||
MethodElementImpl method = ElementFactory.methodElement(methodName, null);
|
||||
ParameterElement parameter = ElementFactory.namedParameter(parameterName);
|
||||
method.parameters = <ParameterElement>[parameter];
|
||||
classA.methods = <MethodElement>[method];
|
||||
SimpleIdentifier left = AstTestFactory.identifier3("i");
|
||||
left.staticType = classA.type;
|
||||
MethodInvocation invocation = AstTestFactory.methodInvocation(
|
||||
left, methodName, [
|
||||
AstTestFactory.namedExpression2(parameterName, AstTestFactory.integer(0))
|
||||
]);
|
||||
_resolveNode(invocation);
|
||||
expect(invocation.methodName.staticElement, same(method));
|
||||
expect(
|
||||
(invocation.argumentList.arguments[0] as NamedExpression)
|
||||
.name
|
||||
.label
|
||||
.staticElement,
|
||||
same(parameter));
|
||||
_listener.assertNoErrors();
|
||||
}
|
||||
|
||||
test_visitPostfixExpression() async {
|
||||
InterfaceType numType = _typeProvider.numType;
|
||||
SimpleIdentifier operand = AstTestFactory.identifier3("i");
|
||||
|
|
|
@ -3980,38 +3980,6 @@ import 'lib1.dart' show a;''');
|
|||
verify([source]);
|
||||
}
|
||||
|
||||
test_undefinedMethod() async {
|
||||
Source source = addSource(r'''
|
||||
f() {
|
||||
var a = 'str';
|
||||
a.notAMethodOnString();
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
if (previewDart2) {
|
||||
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
} else {
|
||||
assertErrors(source, [HintCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
}
|
||||
|
||||
test_undefinedMethod_assignmentExpression() async {
|
||||
Source source = addSource(r'''
|
||||
class A {}
|
||||
class B {
|
||||
f(var a, var a2) {
|
||||
a = new A();
|
||||
a2 = new A();
|
||||
a += a2;
|
||||
}
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
if (previewDart2) {
|
||||
assertNoErrors(source);
|
||||
} else {
|
||||
assertErrors(source, [HintCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
}
|
||||
|
||||
test_undefinedOperator_binaryExpression() async {
|
||||
Source source = addSource(r'''
|
||||
class A {}
|
||||
|
|
|
@ -29,12 +29,6 @@ class NonErrorResolverTest_Driver extends NonErrorResolverTestBase {
|
|||
return super.test_intLiteralInDoubleContext_const_exact();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
test_null_callMethod() {
|
||||
return super.test_null_callMethod();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
test_null_callOperator() {
|
||||
|
|
|
@ -104,12 +104,6 @@ class NonErrorResolverTest extends NonErrorResolverTestBase {
|
|||
return super.test_mixinInference_with_actual_mixins_supermixins_enabled();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
test_null_callMethod() {
|
||||
return super.test_null_callMethod();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
test_null_callOperator() {
|
||||
|
@ -3590,86 +3584,6 @@ class A<E> {
|
|||
verify([source]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_dynamic() async {
|
||||
Source source = addSource(r'''
|
||||
class A {
|
||||
var f;
|
||||
}
|
||||
class B extends A {
|
||||
g() {
|
||||
f();
|
||||
}
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_functionTypeTypeParameter() async {
|
||||
Source source = addSource(r'''
|
||||
typedef void Action<T>(T x);
|
||||
class C<T, U extends Action<T>> {
|
||||
T value;
|
||||
U action;
|
||||
C(this.value, [this.action]);
|
||||
void act() {
|
||||
action(value);
|
||||
}
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_getter() async {
|
||||
Source source = addSource(r'''
|
||||
class A {
|
||||
var g;
|
||||
}
|
||||
f() {
|
||||
A a;
|
||||
a.g();
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_localVariable() async {
|
||||
Source source = addSource(r'''
|
||||
f() {
|
||||
var g;
|
||||
g();
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_localVariable_dynamic() async {
|
||||
Source source = addSource(r'''
|
||||
f() {}
|
||||
main() {
|
||||
var v = f;
|
||||
v();
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_Object() async {
|
||||
Source source = addSource(r'''
|
||||
main() {
|
||||
Object v = null;
|
||||
v();
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
Future test_issue32114() async {
|
||||
addNamedSource('/a.dart', '''
|
||||
class O {}
|
||||
|
@ -4984,15 +4898,6 @@ class A {
|
|||
verify([source]);
|
||||
}
|
||||
|
||||
test_null_callMethod() async {
|
||||
Source source = addSource(r'''
|
||||
main() {
|
||||
null.m();
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_null_callOperator() async {
|
||||
Source source = addSource(r'''
|
||||
main() {
|
||||
|
|
|
@ -930,24 +930,6 @@ class D<T extends dynamic> {
|
|||
assertNoErrors(source);
|
||||
}
|
||||
|
||||
test_undefinedMethod_inSubtype() async {
|
||||
Source source = addSource(r'''
|
||||
class A {}
|
||||
class B extends A {
|
||||
b() {}
|
||||
}
|
||||
f() {
|
||||
var a = new A();
|
||||
a.b();
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
if (previewDart2) {
|
||||
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
} else {
|
||||
assertNoErrors(source);
|
||||
}
|
||||
}
|
||||
|
||||
test_undefinedMethod_unionType_all() async {
|
||||
Source source = addSource(r'''
|
||||
class A {
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
// 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/error/error.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
import 'package:analyzer/src/generated/java_core.dart' show formatList;
|
||||
import 'package:analyzer/src/generated/source_io.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'resolver_test_case.dart';
|
||||
|
@ -95,21 +92,6 @@ E e() {
|
|||
}''', [StaticTypeWarningCode.UNDEFINED_ENUM_CONSTANT]);
|
||||
}
|
||||
|
||||
test_ambiguousImport_function() async {
|
||||
Source source = addSource(r'''
|
||||
import 'lib1.dart';
|
||||
import 'lib2.dart';
|
||||
g() { return f(); }''');
|
||||
addNamedSource("/lib1.dart", r'''
|
||||
library lib1;
|
||||
f() {}''');
|
||||
addNamedSource("/lib2.dart", r'''
|
||||
library lib2;
|
||||
f() {}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.AMBIGUOUS_IMPORT]);
|
||||
}
|
||||
|
||||
test_assert_message_suppresses_type_promotion() async {
|
||||
// If a variable is assigned to inside the expression for an assert
|
||||
// message, type promotion should be suppressed, just as it would be if the
|
||||
|
@ -522,16 +504,6 @@ class C {
|
|||
''', [StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE]);
|
||||
}
|
||||
|
||||
test_instanceAccessToStaticMember_method_invocation() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
static m() {}
|
||||
}
|
||||
main(A a) {
|
||||
a.m();
|
||||
}''', [StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER]);
|
||||
}
|
||||
|
||||
test_instanceAccessToStaticMember_method_reference() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
|
@ -682,85 +654,6 @@ class A {
|
|||
}''', [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_class() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
void m() {
|
||||
A();
|
||||
}
|
||||
}''', previewDart2 ? [] : [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_dynamic() async {
|
||||
await assertErrorsInCode(r'''
|
||||
main() {
|
||||
dynamic d;
|
||||
d.hashCode();
|
||||
}
|
||||
''', [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_localGenericFunction() async {
|
||||
// Invoking `.call` on a `Function` type works similarly to invoking it on
|
||||
// `dynamic`--the invocation is accepted at compile time, and all type
|
||||
// checking is deferred until runtime.
|
||||
await assertErrorsInCode('''
|
||||
f(Function f) {
|
||||
return f();
|
||||
}''', []);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_localObject() async {
|
||||
await assertErrorsInCode('''
|
||||
f(Object o) {
|
||||
return o();
|
||||
}''', [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_localVariable() async {
|
||||
await assertErrorsInCode(r'''
|
||||
f() {
|
||||
int x;
|
||||
return x();
|
||||
}''', [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_ordinaryInvocation() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
static int x;
|
||||
}
|
||||
class B {
|
||||
m() {
|
||||
A.x();
|
||||
}
|
||||
}''', [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
// A call to verify(source) fails as A.x() cannot be resolved.
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_staticInvocation() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
static int get g => 0;
|
||||
f() {
|
||||
A.g();
|
||||
}
|
||||
}''', [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
// A call to verify(source) fails as g() cannot be resolved.
|
||||
}
|
||||
|
||||
test_invocationOfNonFunction_superExpression() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
int get g => 0;
|
||||
}
|
||||
class B extends A {
|
||||
m() {
|
||||
var v = super.g();
|
||||
}
|
||||
}''', [StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION]);
|
||||
}
|
||||
|
||||
test_invocationOfNonFunctionExpression_literal() async {
|
||||
await assertErrorsInCode(r'''
|
||||
f() {
|
||||
|
@ -1413,34 +1306,6 @@ main(A<V> p) {
|
|||
}''', [StaticTypeWarningCode.UNDEFINED_GETTER]);
|
||||
}
|
||||
|
||||
test_undefinedFunction() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f() {
|
||||
g();
|
||||
}''', [StaticTypeWarningCode.UNDEFINED_FUNCTION]);
|
||||
}
|
||||
|
||||
test_undefinedFunction_inCatch() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f() {
|
||||
try {
|
||||
} on Object {
|
||||
g();
|
||||
}
|
||||
}''', [StaticTypeWarningCode.UNDEFINED_FUNCTION]);
|
||||
}
|
||||
|
||||
test_undefinedFunction_inImportedLib() async {
|
||||
Source source = addSource(r'''
|
||||
import 'lib.dart' as f;
|
||||
main() { return f.g(); }''');
|
||||
addNamedSource("/lib.dart", r'''
|
||||
library lib;
|
||||
h() {}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_FUNCTION]);
|
||||
}
|
||||
|
||||
test_undefinedGetter() async {
|
||||
await assertErrorsInUnverifiedCode(r'''
|
||||
class T {}
|
||||
|
@ -1536,15 +1401,6 @@ main(A<NoSuchType> a) {
|
|||
}''', [StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT]);
|
||||
}
|
||||
|
||||
test_undefinedMethod() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
void m() {
|
||||
n();
|
||||
}
|
||||
}''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_assignmentExpression() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {}
|
||||
|
@ -1556,17 +1412,6 @@ class B {
|
|||
}''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_generic_function_call() async {
|
||||
// Invoking `.call` on a `Function` type works similarly to invoking it on
|
||||
// `dynamic`--the invocation is accepted at compile time, and all type
|
||||
// checking is deferred until runtime.
|
||||
await assertErrorsInCode('''
|
||||
f(Function f) {
|
||||
f.call();
|
||||
}
|
||||
''', []);
|
||||
}
|
||||
|
||||
test_undefinedMethod_ignoreTypePropagation() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {}
|
||||
|
@ -1586,14 +1431,6 @@ class C {
|
|||
[StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_object_call() async {
|
||||
await assertErrorsInCode('''
|
||||
f(Object o) {
|
||||
o.call();
|
||||
}
|
||||
''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_ofNull() async {
|
||||
// TODO(scheglov) Track https://github.com/dart-lang/sdk/issues/28430 to
|
||||
// decide whether a warning should be reported here.
|
||||
|
@ -1605,54 +1442,6 @@ main() {
|
|||
''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_private() async {
|
||||
addNamedSource("/lib.dart", r'''
|
||||
library lib;
|
||||
class A {
|
||||
_foo() {}
|
||||
}''');
|
||||
await assertErrorsInCode(r'''
|
||||
import 'lib.dart';
|
||||
class B extends A {
|
||||
test() {
|
||||
_foo();
|
||||
}
|
||||
}''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_proxy_annotation_fakeProxy() async {
|
||||
await assertErrorsInCode(r'''
|
||||
library L;
|
||||
class Fake {
|
||||
const Fake();
|
||||
}
|
||||
const proxy = const Fake();
|
||||
@proxy class PrefixProxy {}
|
||||
main() {
|
||||
new PrefixProxy().foo();
|
||||
}''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_typeLiteral_cascadeTarget() async {
|
||||
await assertErrorsInCode('''
|
||||
class T {
|
||||
static void foo() {}
|
||||
}
|
||||
main() {
|
||||
T..foo();
|
||||
}
|
||||
''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethod_typeLiteral_conditionalAccess() async {
|
||||
// When applied to a type literal, the conditional access operator '?.'
|
||||
// cannot be used to access instance methods of Type.
|
||||
await assertErrorsInCode('''
|
||||
class A {}
|
||||
f() => A?.toString();
|
||||
''', [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedMethodWithConstructor() async {
|
||||
// TODO(brianwilkerson) We cannot verify in previewDart2 because 'C' could
|
||||
// not be resolved.
|
||||
|
@ -1766,18 +1555,6 @@ class B extends A {
|
|||
''', [StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER]);
|
||||
}
|
||||
|
||||
test_unqualifiedReferenceToNonLocalStaticMember_method() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
static void a() {}
|
||||
}
|
||||
class B extends A {
|
||||
void b() {
|
||||
a();
|
||||
}
|
||||
}''', [StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER]);
|
||||
}
|
||||
|
||||
test_unqualifiedReferenceToNonLocalStaticMember_setter() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
|
@ -1948,26 +1725,6 @@ class StrongModeStaticTypeWarningCodeTest extends ResolverTestCase {
|
|||
resetWith(options: options);
|
||||
}
|
||||
|
||||
test_genericMethodWrongNumberOfTypeArguments() async {
|
||||
Source source = addSource('''
|
||||
f() {}
|
||||
main() {
|
||||
f<int>();
|
||||
}
|
||||
''');
|
||||
TestAnalysisResult analysisResult = await computeAnalysisResult(source);
|
||||
assertErrors(
|
||||
source, [StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD]);
|
||||
for (AnalysisError error in analysisResult.errors) {
|
||||
if (error.errorCode ==
|
||||
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS) {
|
||||
expect(error.message,
|
||||
formatList(error.errorCode.message, ['() → dynamic', 0, 1]));
|
||||
}
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_legalAsyncGeneratorReturnType_function_supertypeOfStream() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
|
|
@ -275,24 +275,6 @@ var v;''');
|
|||
assertErrors(source, [StaticWarningCode.AMBIGUOUS_IMPORT]);
|
||||
}
|
||||
|
||||
test_ambiguousImport_withPrefix() async {
|
||||
Source source = addSource(r'''
|
||||
library test;
|
||||
import 'lib1.dart' as p;
|
||||
import 'lib2.dart' as p;
|
||||
main() {
|
||||
p.f();
|
||||
}''');
|
||||
addNamedSource("/lib1.dart", r'''
|
||||
library lib1;
|
||||
f() {}''');
|
||||
addNamedSource("/lib2.dart", r'''
|
||||
library lib2;
|
||||
f() {}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.AMBIGUOUS_IMPORT]);
|
||||
}
|
||||
|
||||
test_argumentTypeNotAssignable_ambiguousClassName() async {
|
||||
// See dartbug.com/19624
|
||||
Source source = addNamedSource("/lib1.dart", r'''
|
||||
|
@ -1342,51 +1324,6 @@ void main() {
|
|||
}
|
||||
}
|
||||
|
||||
test_generalizedVoid_invocationOfVoidFieldError() async {
|
||||
Source source = addSource(r'''
|
||||
class Container<T>{
|
||||
T value;
|
||||
}
|
||||
void main(Container<void> voidContainer) {
|
||||
voidContainer.value();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_invocationOfVoidLocalError() async {
|
||||
Source source = addSource(r'''
|
||||
void main() {
|
||||
void x;
|
||||
x();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_invocationOfVoidResultError() async {
|
||||
Source source = addSource(r'''
|
||||
void main() {
|
||||
main()();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_invocationOfVoidToplevelError() async {
|
||||
Source source = addSource(r'''
|
||||
void x;
|
||||
void main() {
|
||||
x();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_negateVoidValueError() async {
|
||||
Source source = addSource(r'''
|
||||
void main() {
|
||||
|
@ -1534,28 +1471,6 @@ void main() {
|
|||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_useOfVoidCallMethodError() async {
|
||||
Source source = addSource(r'''
|
||||
void main() {
|
||||
void x;
|
||||
x.toString();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_useOfVoidCallMethodWithNullError() async {
|
||||
Source source = addSource(r'''
|
||||
void main() {
|
||||
void x;
|
||||
x?.toString();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_useOfVoidCallSetterError() async {
|
||||
Source source = addSource(r'''
|
||||
void main() {
|
||||
|
@ -1567,17 +1482,6 @@ void main() {
|
|||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_useOfVoidCascadeError() async {
|
||||
Source source = addSource(r'''
|
||||
void main() {
|
||||
void x;
|
||||
x..toString();
|
||||
}
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticWarningCode.USE_OF_VOID_RESULT]);
|
||||
}
|
||||
|
||||
test_generalizedVoid_useOfVoidCastsOk() async {
|
||||
Source source = addSource(r'''
|
||||
void use(dynamic x) { }
|
||||
|
@ -3991,29 +3895,6 @@ f(var p) {
|
|||
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
|
||||
}
|
||||
|
||||
test_undefinedStaticMethodOrGetter_method() async {
|
||||
Source source = addSource(r'''
|
||||
class C {}
|
||||
f(var p) {
|
||||
f(C.m());
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedStaticMethodOrGetter_method_inSuperclass() async {
|
||||
Source source = addSource(r'''
|
||||
class S {
|
||||
static m() {}
|
||||
}
|
||||
class C extends S {}
|
||||
f(var p) {
|
||||
f(C.m());
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
|
||||
}
|
||||
|
||||
test_undefinedStaticMethodOrGetter_setter_inSuperclass() async {
|
||||
Source source = addSource(r'''
|
||||
class S {
|
||||
|
|
|
@ -2927,17 +2927,6 @@ main() {
|
|||
expectInitializerType('foo', 'int');
|
||||
}
|
||||
|
||||
test_dynamicObjectMethod_toString() async {
|
||||
String code = r'''
|
||||
main() {
|
||||
dynamic a = null;
|
||||
var foo = a.toString();
|
||||
}
|
||||
''';
|
||||
await resolveTestUnit(code);
|
||||
expectInitializerType('foo', 'String');
|
||||
}
|
||||
|
||||
test_futureOr_promotion1() async {
|
||||
// Test that promotion from FutureOr<T> to T works for concrete types
|
||||
String code = r'''
|
||||
|
@ -3612,22 +3601,6 @@ class D extends C {
|
|||
verify([source]);
|
||||
}
|
||||
|
||||
test_genericMethod_partiallyAppliedErrorWithBound() async {
|
||||
await resolveTestUnit(r'''
|
||||
void f<X extends List, Y>() => null;
|
||||
|
||||
void test() {
|
||||
f<int>();
|
||||
}
|
||||
''', noErrors: false);
|
||||
assertErrors(testSource, [
|
||||
// Make sure to catch both the missing parameter:
|
||||
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
|
||||
// And the incorrect parameter:
|
||||
StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
|
||||
]);
|
||||
}
|
||||
|
||||
test_genericMethod_propagatedType_promotion() async {
|
||||
// Regression test for:
|
||||
// https://github.com/dart-lang/sdk/issues/25340
|
||||
|
|
|
@ -3567,7 +3567,6 @@ main() {
|
|||
assertType(aRef, 'int');
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_invalid_methodInvocation_simpleIdentifier() async {
|
||||
addTestFile(r'''
|
||||
int foo = 0;
|
||||
|
@ -5388,8 +5387,8 @@ main(double computation(int p)) {
|
|||
expect(target.staticType.toString(), '(int) → double');
|
||||
|
||||
SimpleIdentifier methodName = invocation.methodName;
|
||||
expect(methodName.staticElement, same(parameter));
|
||||
expect(methodName.staticType, parameter.type);
|
||||
expect(methodName.staticElement, isNull);
|
||||
expect(methodName.staticType, dynamicType);
|
||||
}
|
||||
|
||||
test_methodInvocation_instanceMethod_forwardingStub() async {
|
||||
|
@ -8737,69 +8736,6 @@ main() {
|
|||
expect(identifier.staticType, isDynamicType);
|
||||
}
|
||||
|
||||
test_unresolved_static_call() async {
|
||||
addTestFile('''
|
||||
class C {
|
||||
static f() => C.g();
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
expect(result.errors, isNotEmpty);
|
||||
|
||||
var g = findNode.simple('g()');
|
||||
assertElementNull(g);
|
||||
assertTypeDynamic(g);
|
||||
var invocation = g.parent as MethodInvocation;
|
||||
assertTypeDynamic(invocation);
|
||||
expect(invocation.staticInvokeType, isDynamicType);
|
||||
}
|
||||
|
||||
test_unresolved_static_call_arguments() async {
|
||||
addTestFile('''
|
||||
int x;
|
||||
class C {
|
||||
static f() => C.g(x);
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
expect(result.errors, isNotEmpty);
|
||||
|
||||
var x = findNode.simple('x)');
|
||||
assertElement(x, findElement.topGet('x'));
|
||||
assertType(x, 'int');
|
||||
}
|
||||
|
||||
test_unresolved_static_call_same_name_as_type_param() async {
|
||||
addTestFile('''
|
||||
class C<T> {
|
||||
static f() => C.T();
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
expect(result.errors, isNotEmpty);
|
||||
|
||||
var t = findNode.simple('T()');
|
||||
assertElementNull(t);
|
||||
assertTypeDynamic(t);
|
||||
var invocation = t.parent as MethodInvocation;
|
||||
assertTypeDynamic(invocation);
|
||||
expect(invocation.staticInvokeType, isDynamicType);
|
||||
}
|
||||
|
||||
test_unresolved_static_call_type_arguments() async {
|
||||
addTestFile('''
|
||||
class C {
|
||||
static f() => C.g<int>();
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
expect(result.errors, isNotEmpty);
|
||||
|
||||
var intRef = findNode.simple('int>');
|
||||
assertElement(intRef, intType.element);
|
||||
assertType(intRef, 'int');
|
||||
}
|
||||
|
||||
/// Assert that the [argument] is associated with the [expected]. If the
|
||||
/// [argument] is a [NamedExpression], the name must be resolved to the
|
||||
/// parameter.
|
||||
|
|
|
@ -55,28 +55,7 @@ class Baz extends Bar {
|
|||
assertTestErrors([CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE]);
|
||||
assertElement(
|
||||
findNode.simple('foo; // ref'),
|
||||
findElement.getter('foo', className: 'Foo'),
|
||||
);
|
||||
}
|
||||
|
||||
test_abstractSuperMemberReference_method_invocation() async {
|
||||
addTestFile(r'''
|
||||
abstract class A {
|
||||
foo();
|
||||
}
|
||||
abstract class B extends A {
|
||||
bar() {
|
||||
super.foo(); // ref
|
||||
}
|
||||
|
||||
foo() {} // does not matter
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
assertTestErrors([CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE]);
|
||||
assertElement(
|
||||
findNode.simple('foo(); // ref'),
|
||||
findElement.method('foo', of: 'A'),
|
||||
findElement.getter('foo', of: 'Foo'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -123,31 +102,6 @@ class C extends A with B {
|
|||
);
|
||||
}
|
||||
|
||||
test_abstractSuperMemberReference_OK_mixinHasConcrete2_method() async {
|
||||
addTestFile('''
|
||||
class A {
|
||||
}
|
||||
|
||||
class M {
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
class B = A with M;
|
||||
|
||||
class C extends B {
|
||||
void bar() {
|
||||
super.foo(); // ref
|
||||
}
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
assertNoTestErrors();
|
||||
assertElement(
|
||||
findNode.simple('foo(); // ref'),
|
||||
findElement.method('foo', of: 'M'),
|
||||
);
|
||||
}
|
||||
|
||||
test_abstractSuperMemberReference_OK_superHasConcrete_mixinHasAbstract_method() async {
|
||||
addTestFile('''
|
||||
class A {
|
||||
|
@ -190,31 +144,7 @@ class C extends B {
|
|||
assertNoTestErrors();
|
||||
assertElement(
|
||||
findNode.simple('foo; // ref'),
|
||||
findElement.getter('foo', className: 'A'),
|
||||
);
|
||||
}
|
||||
|
||||
test_abstractSuperMemberReference_OK_superSuperHasConcrete_method() async {
|
||||
addTestFile('''
|
||||
abstract class A {
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
abstract class B extends A {
|
||||
void foo();
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
void bar() {
|
||||
super.foo(); // ref
|
||||
}
|
||||
}
|
||||
''');
|
||||
await resolveTestFile();
|
||||
assertNoTestErrors();
|
||||
assertElement(
|
||||
findNode.simple('foo(); // ref'),
|
||||
findElement.method('foo', of: 'A'),
|
||||
findElement.getter('foo', of: 'A'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -108,9 +108,9 @@ class FindElement {
|
|||
fail('Not found generic type alias: $name');
|
||||
}
|
||||
|
||||
PropertyAccessorElement getter(String name, {String className}) {
|
||||
PropertyAccessorElement getter(String name, {String of}) {
|
||||
for (var class_ in unitElement.types) {
|
||||
if (className != null && class_.name != className) {
|
||||
if (of != null && class_.name != of) {
|
||||
continue;
|
||||
}
|
||||
for (var accessor in class_.accessors) {
|
||||
|
@ -143,6 +143,25 @@ class FindElement {
|
|||
return class_(name).type;
|
||||
}
|
||||
|
||||
FunctionElement localFunction(String name) {
|
||||
FunctionElement result;
|
||||
unit.accept(new FunctionAstVisitor(
|
||||
functionDeclarationStatement: (node) {
|
||||
var element = node.functionDeclaration.declaredElement;
|
||||
if (element is FunctionElement) {
|
||||
if (result != null) {
|
||||
throw new StateError('Local function name $name is not unique.');
|
||||
}
|
||||
result = element;
|
||||
}
|
||||
},
|
||||
));
|
||||
if (result == null) {
|
||||
fail('Not found local function: $name');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LocalVariableElement localVar(String name) {
|
||||
LocalVariableElement result;
|
||||
unit.accept(new FunctionAstVisitor(
|
||||
|
|
|
@ -7,10 +7,23 @@ import 'package:analyzer/dart/ast/visitor.dart';
|
|||
|
||||
/// [RecursiveAstVisitor] that delegates visit methods to functions.
|
||||
class FunctionAstVisitor extends RecursiveAstVisitor<void> {
|
||||
final void Function(FunctionDeclarationStatement)
|
||||
functionDeclarationStatement;
|
||||
final void Function(SimpleIdentifier) simpleIdentifier;
|
||||
final void Function(VariableDeclaration) variableDeclaration;
|
||||
|
||||
FunctionAstVisitor({this.simpleIdentifier, this.variableDeclaration});
|
||||
FunctionAstVisitor(
|
||||
{this.functionDeclarationStatement,
|
||||
this.simpleIdentifier,
|
||||
this.variableDeclaration});
|
||||
|
||||
@override
|
||||
void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
|
||||
if (functionDeclarationStatement != null) {
|
||||
functionDeclarationStatement(node);
|
||||
}
|
||||
super.visitFunctionDeclarationStatement(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSimpleIdentifier(SimpleIdentifier node) {
|
||||
|
|
1672
pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
Normal file
1672
pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -61,6 +61,16 @@ abstract class ResolutionTest implements ResourceProviderMixin {
|
|||
newFile('/test/lib/test.dart', content: content);
|
||||
}
|
||||
|
||||
/// Assert that the given [identifier] is a reference to a class, in the
|
||||
/// form that is not a separate expression, e.g. in a static method
|
||||
/// invocation like `C.staticMethod()`, or a type annotation `C c = null`.
|
||||
void assertClassRef(
|
||||
SimpleIdentifier identifier, ClassElement expectedElement) {
|
||||
assertElement(identifier, expectedElement);
|
||||
// TODO(scheglov) Enforce this.
|
||||
// assertTypeNull(identifier);
|
||||
}
|
||||
|
||||
void assertConstructorElement(
|
||||
ConstructorElement expected, ConstructorElement actual) {
|
||||
if (expected is ConstructorMember && actual is ConstructorMember) {
|
||||
|
@ -168,6 +178,11 @@ abstract class ResolutionTest implements ResourceProviderMixin {
|
|||
assertType(ref, type);
|
||||
}
|
||||
|
||||
void assertImportPrefix(SimpleIdentifier identifier, PrefixElement element) {
|
||||
assertElement(identifier, element);
|
||||
assertTypeNull(identifier);
|
||||
}
|
||||
|
||||
void assertInstanceCreation(InstanceCreationExpression creation,
|
||||
ClassElement expectedClassElement, String expectedType,
|
||||
{String constructorName,
|
||||
|
@ -232,10 +247,51 @@ abstract class ResolutionTest implements ResourceProviderMixin {
|
|||
expect(actual.baseElement, same(expectedBase));
|
||||
}
|
||||
|
||||
void assertMethodInvocation(MethodInvocation invocation,
|
||||
Element expectedElement, String expectedInvokeType,
|
||||
{String expectedNameType, String expectedType}) {
|
||||
// TODO(scheglov) Check for Member.
|
||||
var element = invocation.methodName.staticElement;
|
||||
if (element is Member) {
|
||||
element = (element as Member).baseElement;
|
||||
expect(element, same(expectedElement));
|
||||
} else {
|
||||
assertElement(invocation.methodName, expectedElement);
|
||||
}
|
||||
|
||||
// TODO(scheglov) Should we enforce this?
|
||||
// if (expectedNameType == null) {
|
||||
// if (expectedElement is ExecutableElement) {
|
||||
// expectedNameType = expectedElement.type.displayName;
|
||||
// } else if (expectedElement is VariableElement) {
|
||||
// expectedNameType = expectedElement.type.displayName;
|
||||
// }
|
||||
// }
|
||||
// assertType(invocation.methodName, expectedNameType);
|
||||
|
||||
assertInvokeType(invocation, expectedInvokeType);
|
||||
|
||||
expectedType ??= _extractReturnType(expectedInvokeType);
|
||||
assertType(invocation, expectedType);
|
||||
}
|
||||
|
||||
void assertNamedParameterRef(String search, String name) {
|
||||
var ref = findNode.simple(search);
|
||||
assertElement(ref, findElement.parameter(name));
|
||||
assertTypeNull(ref);
|
||||
}
|
||||
|
||||
void assertNoTestErrors() {
|
||||
assertTestErrors(const <ErrorCode>[]);
|
||||
}
|
||||
|
||||
void assertSuperExpression(SuperExpression superExpression) {
|
||||
// TODO(scheglov) I think `super` does not have type itself.
|
||||
// It is just a signal to look for implemented method in the supertype.
|
||||
// With mixins there isn't a type anyway.
|
||||
// assertTypeNull(superExpression);
|
||||
}
|
||||
|
||||
void assertTestErrors(List<ErrorCode> expected) {
|
||||
assertErrors(result.errors, expected);
|
||||
}
|
||||
|
@ -334,6 +390,12 @@ abstract class ResolutionTest implements ResourceProviderMixin {
|
|||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
static String _extractReturnType(String invokeType) {
|
||||
int arrowIndex = invokeType.indexOf('→');
|
||||
expect(arrowIndex, isNonNegative);
|
||||
return invokeType.substring(arrowIndex + 1).trim();
|
||||
}
|
||||
}
|
||||
|
||||
class TestAnalysisResult {
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:test_reflective_loader/test_reflective_loader.dart';
|
|||
|
||||
import 'assignment_test.dart' as assignment_test;
|
||||
import 'class_test.dart' as class_test;
|
||||
import 'optional_const_test.dart' as optional_const_test;
|
||||
import 'enum_test.dart' as enum_test;
|
||||
import 'for_in_test.dart' as for_in_test;
|
||||
import 'generic_type_alias_test.dart' as generic_type_alias_test;
|
||||
|
@ -16,7 +15,9 @@ import 'instance_member_inference_class_test.dart'
|
|||
as instance_member_inference_class_test;
|
||||
import 'instance_member_inference_mixin_test.dart'
|
||||
as instance_member_inference_mixin_test;
|
||||
import 'method_invocation_test.dart' as method_invocation_test;
|
||||
import 'mixin_test.dart' as mixin_test;
|
||||
import 'optional_const_test.dart' as optional_const_test;
|
||||
import 'top_type_inference_test.dart' as top_type_inference_test;
|
||||
|
||||
main() {
|
||||
|
@ -30,6 +31,7 @@ main() {
|
|||
instance_creation_test.main();
|
||||
instance_member_inference_class_test.main();
|
||||
instance_member_inference_mixin_test.main();
|
||||
method_invocation_test.main();
|
||||
mixin_test.main();
|
||||
optional_const_test.main();
|
||||
top_type_inference_test.main();
|
||||
|
|
|
@ -4483,24 +4483,10 @@ class InferredTypeTest_Driver extends AbstractStrongTest
|
|||
.test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1();
|
||||
}
|
||||
|
||||
@failingTest
|
||||
@override
|
||||
test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr2() async {
|
||||
await super
|
||||
.test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr2();
|
||||
}
|
||||
|
||||
@failingTest
|
||||
@override
|
||||
test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1() {
|
||||
return super
|
||||
.test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1();
|
||||
}
|
||||
|
||||
@failingTest
|
||||
@override
|
||||
test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr2() async {
|
||||
await super
|
||||
.test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr2();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@ accessor_conflict_import2_test: CompileTimeError # Issue 25626
|
|||
accessor_conflict_import_prefixed2_test: CompileTimeError # Issue 25626
|
||||
accessor_conflict_import_prefixed_test: CompileTimeError # Issue 25626
|
||||
accessor_conflict_import_test: CompileTimeError # Issue 25626
|
||||
additional_interface_adds_optional_args_test: CompileTimeError # Issue #30568
|
||||
bug32372_test: Skip
|
||||
cascaded_forwarding_stubs_test: CompileTimeError # Issue 34329
|
||||
config_import_corelib_test: CompileTimeError, StaticWarning, OK # failing-by-design: Will never pass, see Issue #34332
|
||||
conflicting_generic_interfaces_hierarchy_loop_infinite_test: Skip # Issue #34333 (loops forever)
|
||||
|
@ -77,7 +75,6 @@ issue34498_test: MissingCompileTimeError # Issue 34500
|
|||
large_class_declaration_test: Slow, Pass
|
||||
malformed2_test: Pass, MissingCompileTimeError # Flaky: issue 31056.
|
||||
mixin_declaration/mixin_declaration_factory_test/02: Crash # Issue 34809
|
||||
mixin_declaration/mixin_declaration_invalid_superinvocation_test/10: CompileTimeError # Issue 30552
|
||||
mixin_method_override_test/01: MissingCompileTimeError
|
||||
mixin_of_mixin_test: Skip
|
||||
mixin_super_2_test: Skip
|
||||
|
@ -105,7 +102,6 @@ mixin_type_parameter_inference_error_test: Skip
|
|||
mixin_type_parameter_inference_previous_mixin_test: Skip
|
||||
mixin_type_parameter_inference_test: Skip
|
||||
mock_writable_final_private_field_test: CompileTimeError # failing-by-design, see Issue #34377
|
||||
multiple_interface_inheritance_test: CompileTimeError # Issue 30552
|
||||
nested_generic_closure_test: CompileTimeError # Issue #28515
|
||||
no_main_test/01: Fail # failing-by-design, the analyzer has no restriction that a library include a main function.
|
||||
no_such_constructor2_test: StaticWarning
|
||||
|
@ -122,7 +118,6 @@ regress_27617_test/1: MissingCompileTimeError
|
|||
regress_29025_test: CompileTimeError # Issue 29081
|
||||
regress_29405_test: CompileTimeError # Issue 29421
|
||||
regress_29784_test/02: MissingCompileTimeError # Issue 29784
|
||||
regress_30121_test: CompileTimeError # Issue 31087
|
||||
regress_30339_test: CompileTimeError
|
||||
regress_33479_test/01: Crash # Issue #33479
|
||||
setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
|
||||
|
|
|
@ -10,7 +10,6 @@ accessor_conflict_import2_test: CompileTimeError # Issue 25626
|
|||
accessor_conflict_import_prefixed2_test: CompileTimeError # Issue 25626
|
||||
accessor_conflict_import_prefixed_test: CompileTimeError # Issue 25626
|
||||
accessor_conflict_import_test: CompileTimeError # Issue 25626
|
||||
additional_interface_adds_optional_args_test: CompileTimeError # Issue #30568
|
||||
assertion_test: RuntimeError # Issue 30326; Expect.equals(expected: <1>, actual: <0>) fails.
|
||||
async_star_test/01: RuntimeError
|
||||
async_star_test/03: RuntimeError
|
||||
|
@ -89,7 +88,7 @@ invalid_returns/sync_invalid_return_02_test/none: CompileTimeError # issue #3431
|
|||
invalid_returns/sync_invalid_return_03_test/none: CompileTimeError # issue #34319
|
||||
invalid_returns/sync_invalid_return_04_test/none: CompileTimeError # issue #34319
|
||||
invalid_returns/sync_invalid_return_05_test/none: CompileTimeError # issue #34319
|
||||
issue31596_implement_covariant_test: CompileTimeError
|
||||
issue31596_implement_covariant_test: CompileTimeError # Issue #31596
|
||||
issue31596_override_test/01: CompileTimeError
|
||||
issue31596_override_test/02: CompileTimeError
|
||||
issue31596_override_test/03: CompileTimeError
|
||||
|
@ -152,7 +151,6 @@ mixin_declaration/mixin_declaration_inference_valid_C11_test: CompileTimeError #
|
|||
mixin_declaration/mixin_declaration_inference_valid_C12_test: CompileTimeError # Issue #34164
|
||||
mixin_declaration/mixin_declaration_inference_valid_C13_test: CompileTimeError # Issue #34164
|
||||
mixin_declaration/mixin_declaration_inference_valid_mixin_applications_test: CompileTimeError # https://github.com/dart-lang/sdk/issues/34164
|
||||
mixin_declaration/mixin_declaration_invalid_superinvocation_test/10: CompileTimeError # Analyzer chooses wrong(?) super method.
|
||||
mixin_method_override_test/01: MissingCompileTimeError
|
||||
mixin_of_mixin_test: Skip
|
||||
mixin_super_2_test: Skip
|
||||
|
@ -184,7 +182,6 @@ mixin_type_parameter_inference_test/07: MissingCompileTimeError
|
|||
mixin_type_parameter_inference_test/08: RuntimeError
|
||||
mixin_type_parameter_inference_test/09: RuntimeError
|
||||
mock_writable_final_private_field_test: CompileTimeError # Issue 30848
|
||||
multiple_interface_inheritance_test: CompileTimeError # Issue 30552
|
||||
nested_generic_closure_test: CompileTimeError
|
||||
override_inheritance_field_test/42: CompileTimeError
|
||||
part_of_multiple_libs_test/01: MissingCompileTimeError
|
||||
|
@ -199,7 +196,6 @@ regress_29025_test: CompileTimeError # Issue 29081
|
|||
regress_29405_test: CompileTimeError # Issue 29421
|
||||
regress_29784_test/02: Crash # assert initializers not implemented
|
||||
regress_29784_test/02: MissingCompileTimeError
|
||||
regress_30121_test: CompileTimeError # Issue 31087
|
||||
regress_30339_test: CompileTimeError # As expected. Should we make this a multi test?
|
||||
regress_33479_test/01: Crash # Issue #33479
|
||||
setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
|
||||
|
|
Loading…
Reference in a new issue