diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java index 83e0e1e61990..b4a5cb565659 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrSafeCastExpression.java @@ -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); } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java index 8fdfeb29f75b..ef4a8b6b5b85 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrUnaryExpression.java @@ -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); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java index f2f92fd1583a..0666b582ee64 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrBinaryExpressionImpl.java @@ -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); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index 021d0f4b7a83..ba4aae199259 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -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; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrPostfixExprImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrPostfixExprImpl.java index fc0d6e1ceda0..f5f2092ad9be 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrPostfixExprImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrPostfixExprImpl.java @@ -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); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java index 0e01ce54831d..beed9adc3bc0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/arithmetic/GrUnaryExpressionImpl.java @@ -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 TYPE_CALCULATOR = new Function() { + @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 OUR_RESOLVER = + new ResolveCache.PolyVariantResolver() { + @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; + } } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java index 5f6d640aea82..8e10553ec679 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java @@ -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() { }