Unary expression resolve and type inference

This commit is contained in:
Maxim Medvedev
2011-03-17 17:30:00 +03:00
parent a2231537db
commit 46e54ae83b
7 changed files with 156 additions and 44 deletions
@@ -16,12 +16,19 @@
package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions;
import com.intellij.psi.PsiPolyVariantReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
/**
* @author ven
*/
public interface GrSafeCastExpression extends GrExpression {
public interface GrSafeCastExpression extends GrExpression, PsiPolyVariantReference {
GrTypeElement getCastTypeElement();
GrExpression getOperand();
@NotNull
@Override
GroovyResolveResult[] multiResolve(final boolean incompleteCode);
}
@@ -16,16 +16,23 @@
package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
/**
* @author ilyas
*/
public interface GrUnaryExpression extends GrExpression {
public String toString();
public interface GrUnaryExpression extends GrExpression, PsiPolyVariantReference {
IElementType getOperationTokenType();
PsiElement getOperationToken();
@Nullable GrExpression getOperand();
@NotNull
@Override
GroovyResolveResult[] multiResolve(final boolean incompleteCode);
}
@@ -54,13 +54,18 @@ public abstract class GrBinaryExpressionImpl extends GrExpressionImpl implements
@Nullable
public IElementType getOperationTokenType() {
final PsiElement child = findChildByType(TokenSets.BINARY_OP_SET);
final PsiElement child = getOperationToken();
if (child == null) return null;
final ASTNode node = child.getNode();
assert node != null;
return node.getElementType();
}
public PsiElement getOperationToken() {
final PsiElement child = findChildByType(TokenSets.BINARY_OP_SET);
return child;
}
public void accept(GroovyElementVisitor visitor) {
visitor.visitBinaryExpression(this);
}
@@ -345,17 +345,17 @@ public class TypesUtil {
@Nullable
public static PsiType getTypeForIncOrDecExpression(GrUnaryExpression expr) {
final GrExpression op = expr.getOperand();
if (op != null) {
final PsiType opType = op.getType();
if (opType != null) {
final PsiType overloaded = getOverloadedOperatorType(opType, expr.getOperationTokenType(), expr, PsiType.EMPTY_ARRAY);
if (overloaded != null) {
return overloaded;
}
if (isNumericType(opType)) {
return opType;
}
}
if (op == null) return null;
final PsiType opType = op.getType();
if (opType == null) return null;
final PsiType overloaded = getOverloadedOperatorType(opType, expr.getOperationTokenType(), expr, PsiType.EMPTY_ARRAY);
if (overloaded != null) {
return overloaded;
}
if (isNumericType(opType)) {
return opType;
}
return null;
@@ -17,11 +17,9 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrPostfixExpression;
/**
* @author ilyas
@@ -36,10 +34,6 @@ public class GrPostfixExprImpl extends GrUnaryExpressionImpl implements GrPostfi
return "Postfix expression";
}
public PsiType getType() {
return TypesUtil.getTypeForIncOrDecExpression(this);
}
public void accept(GroovyElementVisitor visitor) {
visitor.visitPostfixExpression(this);
}
@@ -17,22 +17,70 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiType;
import com.intellij.psi.impl.source.resolve.ResolveCache;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrExpressionImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
/**
* @author ilyas
*/
public class GrUnaryExpressionImpl extends GrExpressionImpl implements GrUnaryExpression {
private static final String PATTERN_FQ_NAME = "java.util.regex.Pattern";
private static final Function<GrUnaryExpressionImpl,PsiType> TYPE_CALCULATOR = new Function<GrUnaryExpressionImpl, PsiType>() {
@Nullable
@Override
public PsiType fun(GrUnaryExpressionImpl unary) {
GrExpression operand = unary.getOperand();
if (operand == null) return null;
PsiType opType = operand.getType();
if (opType == null) return null;
IElementType opToken = unary.getOperationTokenType();
if (opToken == GroovyTokenTypes.mINC || opToken == GroovyTokenTypes.mDEC) {
return TypesUtil.getTypeForIncOrDecExpression(unary);
}
if (opToken == GroovyTokenTypes.mBNOT && opType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
return unary.getTypeByFQName(GroovyCommonClassNames.JAVA_UTIL_REGEX_PATTERN);
}
return opType;
}
};
private static final ResolveCache.PolyVariantResolver<GrUnaryExpressionImpl> OUR_RESOLVER =
new ResolveCache.PolyVariantResolver<GrUnaryExpressionImpl>() {
@Override
public GroovyResolveResult[] resolve(GrUnaryExpressionImpl unary, boolean incompleteCode) {
final GrExpression operand = unary.getOperand();
if (operand == null) return GroovyResolveResult.EMPTY_ARRAY;
final PsiType type = operand.getType();
if (type == null) return GroovyResolveResult.EMPTY_ARRAY;
return TypesUtil.getOverloadedOperatorCandidates(type, unary.getOperationTokenType(), unary, PsiType.EMPTY_ARRAY);
}
};
public GrUnaryExpressionImpl(@NotNull ASTNode node) {
super(node);
@@ -43,32 +91,22 @@ public class GrUnaryExpressionImpl extends GrExpressionImpl implements GrUnaryEx
}
public PsiType getType() {
IElementType opToken = getOperationTokenType();
GrExpression operand = getOperand();
if (operand == null) return null;
if (opToken == GroovyTokenTypes.mINC || opToken == GroovyTokenTypes.mDEC) {
return TypesUtil.getTypeForIncOrDecExpression(this);
}
PsiType opType = operand.getType();
if (opType == null) return null;
if (opToken == GroovyTokenTypes.mBNOT) {
if (opType.equalsToText("java.lang.String")) {
return getTypeByFQName(PATTERN_FQ_NAME);
}
}
return opType;
return GroovyPsiManager.getInstance(getProject()).getType(this, TYPE_CALCULATOR);
}
public IElementType getOperationTokenType() {
PsiElement opElement = findChildByType(GroovyTokenTypes.UNARY_OP_SET);
assert opElement != null;
PsiElement opElement = getOperationToken();
ASTNode node = opElement.getNode();
assert node != null;
return node.getElementType();
}
public PsiElement getOperationToken() {
PsiElement opElement = findChildByType(GroovyTokenTypes.UNARY_OP_SET);
assert opElement != null;
return opElement;
}
public GrExpression getOperand() {
return findChildByClass(GrExpression.class);
}
@@ -76,4 +114,64 @@ public class GrUnaryExpressionImpl extends GrExpressionImpl implements GrUnaryEx
public void accept(GroovyElementVisitor visitor) {
visitor.visitUnaryExpression(this);
}
@NotNull
@Override
public GroovyResolveResult[] multiResolve(boolean incompleteCode) {
return (GroovyResolveResult[])getManager().getResolveCache().resolveWithCaching(this, OUR_RESOLVER, false, incompleteCode);
}
@Override
public PsiElement getElement() {
return this;
}
@Override
public TextRange getRangeInElement() {
final PsiElement opToken = getOperationToken();
final int offset = opToken.getStartOffsetInParent();
return new TextRange(offset, offset + opToken.getTextLength());
}
@Override
public PsiElement resolve() {
return PsiImplUtil.extractUniqueElement(multiResolve(false));
}
@NotNull
@Override
public String getCanonicalText() {
return getText();
}
@Override
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
throw new IncorrectOperationException("unary expression cannot be renamed to anything");
}
@Override
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
throw new IncorrectOperationException("unary expression cannot be bounded to anything");
}
@Override
public boolean isReferenceTo(PsiElement element) {
return getManager().areElementsEquivalent(resolve(), element);
}
@NotNull
@Override
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@Override
public boolean isSoft() {
return false;
}
@Override
public PsiReference getReference() {
return this;
}
}
@@ -29,6 +29,7 @@ public final class GroovyCommonClassNames {
public static final String GROOVY_LANG_INT_RANGE = "groovy.lang.IntRange";
public static final String GROOVY_LANG_OBJECT_RANGE = "groovy.lang.ObjectRange";
public static final String GROOVY_LANG_DELEGATE = "groovy.lang.Delegate";
public static final String JAVA_UTIL_REGEX_PATTERN = "java.util.regex.Pattern";
private GroovyCommonClassNames() {
}