package com.intellij.lang.javascript.flex;
import com.intellij.lang.javascript.JavaScriptSupportLoader;
import com.intellij.lang.javascript.psi.*;
import com.intellij.lang.javascript.psi.ecmal4.JSClass;
import com.intellij.lang.javascript.psi.resolve.JSResolveUtil;
import com.intellij.lang.javascript.psi.types.*;
import com.intellij.lang.javascript.validation.ValidateTypesUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class ActionScriptExpectedTypeEvaluator extends ExpectedTypeEvaluator {
public ActionScriptExpectedTypeEvaluator(JSExpression parent) {
super(parent);
}
@Override
protected ActionScriptExpectedTypeEvaluator newExpectedTypeEvaluator(JSExpression parent) {
return new ActionScriptExpectedTypeEvaluator(parent);
}
@Override
protected void findRestParameterExpectedType(JSParameterItem parameterItem) {
if (!(parameterItem instanceof JSParameter)) {
super.findRestParameterExpectedType(parameterItem);
return;
}
final JSParameter param = (JSParameter)parameterItem;
final JSFunction fun = param.getDeclaringFunction();
if (fun == null) {
super.findRestParameterExpectedType(parameterItem);
return;
}
PsiElement element = JSResolveUtil.findParent(fun);
JSType classType = element instanceof JSClass ?
JSNamedType.createType(((JSClass)element).getQualifiedName(), JSTypeSource.EMPTY, JSContext.INSTANCE) :
null;
if (classType != null && JSTypeUtils.isActionScriptVectorType(classType)) {
String name = fun.getName();
JSType qualifiedExpressionType = null;
JSExpression methodExpression =
((JSCallExpression)JSTypeUtils.getScopeInOriginalTree(myGrandParent).getParent()).getMethodExpression();
if (methodExpression instanceof JSReferenceExpression) {
JSExpression qualifier = ((JSReferenceExpression)methodExpression).getQualifier();
if (qualifier != null) {
qualifiedExpressionType = JSResolveUtil.getQualifiedExpressionJSType(qualifier, qualifier.getContainingFile());
}
}
if (qualifiedExpressionType != null) {
if ("push".equals(name) || "unshift".equals(name) || "splice".equals(name)) {
if (qualifiedExpressionType instanceof JSGenericTypeImpl) {
myResult = ContainerUtil.getFirstItem(((JSGenericTypeImpl)qualifiedExpressionType).getArguments());
}
}
else if ("concat".equals(name)) {
myResult = qualifiedExpressionType;
}
}
}
else {
myResult = createNamedType(JSCommonTypeNames.OBJECT_CLASS_NAME, myParent);
}
}
protected void evaluateIndexedAccessType(JSIndexedPropertyAccessExpression node) {
if (isASDictionaryAccess(node)) {
myResult = createNamedType(JSCommonTypeNames.OBJECT_CLASS_NAME, myGrandParent);
}
else {
final JSTypeSource typeSource = JSTypeSourceFactory.createTypeSource(myGrandParent, true);
myResult = new JSCompositeTypeImpl(typeSource,
JSNamedType.createType(JSCommonTypeNames.INT_TYPE_NAME, typeSource, JSContext.INSTANCE),
JSNamedType.createType(JSCommonTypeNames.UINT_TYPE_NAME, typeSource, JSContext.INSTANCE));
}
}
private static boolean isASDictionaryAccess(final JSIndexedPropertyAccessExpression expression) {
if (expression.getContainingFile().getLanguage() != JavaScriptSupportLoader.ECMA_SCRIPT_L4) return false;
final JSExpression qualifier = expression.getQualifier();
final PsiElement resolve = qualifier instanceof JSReferenceExpression ? ((JSReferenceExpression)qualifier).resolve() : null;
final String type = resolve instanceof JSVariable ? ((JSVariable)resolve).getTypeString() : null;
return type != null && JSResolveUtil.isAssignableType(ValidateTypesUtil.FLASH_UTILS_DICTIONARY, type, expression);
}
@Override
public void visitJSArgumentList(@NotNull JSArgumentList node) {
JSParameterItem param = JSResolveUtil.findParameterForUsedArgument(myParent, node);
if (param != null) {
if (param.isRest()) {
findRestParameterExpectedType(param);
}
else {
myResult = param.getType();
}
}
}
@Override
public void visitJSArrayLiteralExpression(JSArrayLiteralExpression node) {
if (myGrandParent.getParent() instanceof JSNewExpression) {
JSType type = JSResolveUtil.getQualifiedExpressionJSType((JSExpression)myGrandParent.getParent(), myGrandParent.getContainingFile());
if (type instanceof JSGenericTypeImpl) {
myResult = ContainerUtil.getFirstItem(((JSGenericTypeImpl)type).getArguments());
}
}
}
}