/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.lang.psi.impl.expressions;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightClassReferenceExpression;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import gw.lang.parser.expressions.INewExpression;
import gw.lang.reflect.IConstructorInfo;
import gw.lang.reflect.IErrorType;
import gw.lang.reflect.IType;
import gw.lang.reflect.ITypeVariableType;
import gw.lang.reflect.gs.ICompilableType;
import gw.plugin.ij.lang.parser.GosuCompositeElement;
import gw.plugin.ij.lang.parser.GosuElementTypes;
import gw.plugin.ij.lang.psi.api.expressions.IGosuExpression;
import gw.plugin.ij.lang.psi.impl.GosuElementVisitor;
import gw.plugin.ij.lang.psi.impl.GosuPsiElementImpl;
import gw.plugin.ij.lang.psi.impl.resolvers.PsiFeatureResolver;
import gw.plugin.ij.lang.psi.impl.resolvers.PsiTypeResolver;
import gw.plugin.ij.util.ExecutionUtil;
import gw.plugin.ij.util.SafeCallable;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class GosuNewExpressionImpl extends GosuPsiElementImpl<INewExpression> implements IGosuExpression, PsiNewExpression, PsiModifierListOwner {
public GosuNewExpressionImpl(GosuCompositeElement node) {
super(node);
}
@Override
public PsiType getType() {
IType type = getTypeReferenced();
if (type instanceof IErrorType) {
final GosuTypeLiteralImpl typeLiteral = findChildByClass(GosuTypeLiteralImpl.class);
if (typeLiteral != null) {
return typeLiteral.getType();
}
} else if (type instanceof ICompilableType && ((ICompilableType) type).isAnonymous()) {
IType superType = type.getSupertype();
if (superType == null) {
superType = type.getInterfaces()[0];
}
type = superType;
}
return createType(type);
}
@Nullable
private IType getTypeReferenced() {
final INewExpression element = getParsedElement();
return element != null ? element.getType() : null;
}
@NotNull
@Override
public PsiType[] getTypeArguments() {
return PsiType.EMPTY_ARRAY;
}
@Override
public PsiMethod resolveConstructor() {
PsiElement psiElement = ExecutionUtil.execute(new SafeCallable<PsiElement>(GosuNewExpressionImpl.this) {
@Nullable
public PsiElement execute() throws Exception {
INewExpression newExpr = getParsedElement();
if (newExpr == null) {
return null;
}
IType newExprType = newExpr.getType();
if (newExprType instanceof ITypeVariableType) {
return PsiTypeResolver.resolveTypeVariable((ITypeVariableType) newExprType, GosuNewExpressionImpl.this);
} else {
IConstructorInfo ctor = newExpr.getConstructor();
if (ctor != null && !newExpr.isAnonymousClass()) {
return PsiFeatureResolver.resolveMethodOrConstructor(ctor, GosuNewExpressionImpl.this);
} else {
return null;
}
}
}
});
return psiElement instanceof PsiMethod ? (PsiMethod) psiElement : null;
}
@Override
public PsiExpression getQualifier() {
return null;
}
@NotNull
@Override
public PsiExpression[] getArrayDimensions() {
return PsiExpression.EMPTY_ARRAY;
}
@Override
public PsiJavaCodeReferenceElement getClassReference() {
return null;
}
@Override
public PsiModifierList getModifierList() {
return findChildByClass(PsiModifierList.class);
}
@Override
public boolean hasModifierProperty(@PsiModifier.ModifierConstant @NonNls @NotNull String name) {
PsiModifierListOwner child = findChildByClass(PsiModifierListOwner.class);
if (child != null) {
return child.hasModifierProperty(name);
}
return false;
}
@Nullable
public GosuExpressionListImpl getGosuArgumentList() {
return (GosuExpressionListImpl) findChildByType(GosuElementTypes.ELEM_TYPE_ArgumentListClause);
}
@Override
public PsiArrayInitializerExpression getArrayInitializer() {
return null;
// throw new UnsupportedOperationException("Not implemented yet");
}
@Override
public PsiAnonymousClass getAnonymousClass() {
throw new UnsupportedOperationException("Not implemented yet");
}
@Override
public PsiJavaCodeReferenceElement getClassOrAnonymousClassReference() {
return getClassRefImpl(getType());
}
@Nullable
@Override
public PsiType getOwner(@NotNull PsiAnnotation annotation) {
return null;
}
@Nullable
private PsiJavaCodeReferenceElement getClassRefImpl(@Nullable PsiType psiType) {
if (psiType == null) {
return null;
} else if (psiType instanceof PsiClassReferenceType) {
return ((PsiClassReferenceType) psiType).getReference();
} else if (psiType instanceof PsiImmediateClassType) {
PsiClass psiClass = ((PsiImmediateClassType) psiType).resolve();
return new LightClassReferenceExpression(psiClass.getManager(), "", psiClass);
} else if (psiType instanceof PsiArrayType) {
return getClassRefImpl(((PsiArrayType) psiType).getComponentType());
} else if (psiType instanceof PsiPrimitiveType) {
return null;
} else {
throw new RuntimeException("Unknown psi type " + psiType.getClass().getName());
}
}
@NotNull
@Override
public PsiReferenceParameterList getTypeArgumentList() {
throw new UnsupportedOperationException("Not implemented yet");
}
@Override
public PsiExpressionList getArgumentList() {
return getGosuArgumentList();
}
@Override
public PsiMethod resolveMethod() {
return resolveConstructor();
}
@NotNull
@Override
public JavaResolveResult resolveMethodGenerics() {
throw new UnsupportedOperationException("Not implemented yet");
}
@Override
public void accept( @NotNull PsiElementVisitor visitor ) {
if( visitor instanceof JavaElementVisitor && !(visitor instanceof HighlightVisitorImpl) ) {
((JavaElementVisitor)visitor).visitCallExpression(this);
} else if( visitor instanceof GosuElementVisitor) {
((GosuElementVisitor)visitor).visitNewExpression(this);
} else {
visitor.visitElement( this );
}
}
}