//
// 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.getRealTarget();
if (target instanceof SuperExpression && !isSuperInValidContext((SuperExpression) target)) {
return null;
}
Element staticElement;
Element propagatedElement;
Type staticType = null;
Type propagatedType = null;
if (target == null) {
staticElement = resolveInvokedElement(methodName);
propagatedElement = null;
} else if (methodName.getName().equals(FunctionElement.LOAD_LIBRARY_NAME)
&& isDeferredPrefix(target)) {
LibraryElement importedLibrary = getImportedLibrary(target);
methodName.setStaticElement(importedLibrary.getLoadLibraryFunction());
return null;
} else {
staticType = getStaticType(target);
propagatedType = getPropagatedType(target);
//
// 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.
//
ClassElementImpl typeReference = getTypeReference(target);
if (typeReference != null) {
staticElement = propagatedElement = resolveElement(typeReference, methodName);
} else {
staticElement = resolveInvokedElementWithTarget(target, staticType, methodName);
propagatedElement = resolveInvokedElementWithTarget(target, propagatedType, methodName);
}
}
staticElement = convertSetterToGetter(staticElement);
propagatedElement = convertSetterToGetter(propagatedElement);
//
// Record the results.
//
methodName.setStaticElement(staticElement);
methodName.setPropagatedElement(propagatedElement);
ArgumentList argumentList = node.getArgumentList();
if (staticElement != null) {
ParameterElement[] parameters = computeCorrespondingParameters(argumentList, staticElement);
if (parameters != null) {
argumentList.setCorrespondingStaticParameters(parameters);
}
}
if (propagatedElement != null) {
ParameterElement[] parameters = computeCorrespondingParameters(
argumentList,
propagatedElement);
if (parameters != null) {
argumentList.setCorrespondingPropagatedParameters(parameters);
}
}
//
// Then check for error conditions.
//
ErrorCode errorCode = checkForInvocationError(target, true, staticElement);
boolean generatedWithTypePropagation = false;
if (enableHints && errorCode == null && staticElement == null) {
// The method lookup may have failed because there were multiple
// incompatible choices. In this case we don't want to generate a hint.
if (propagatedElement == null && propagatedType instanceof UnionType) {
// TODO(collinsn): an improvement here is to make the propagated type of the method call
// the union of the propagated types of all possible calls.
if (lookupMethods(target, (UnionType) propagatedType, methodName.getName()).size() > 1) {
return null;
}
}
errorCode = checkForInvocationError(target, false, propagatedElement);
if (errorCode == StaticTypeWarningCode.UNDEFINED_METHOD) {
ClassElement classElementContext = null;
if (target == null) {
classElementContext = resolver.getEnclosingClass();
} else {
Type type = target.getBestType();
if (type != null) {
if (type.getElement() instanceof ClassElement) {
classElementContext = (ClassElement) type.getElement();
}
}