diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java index f3ee89e6203e..d35614470854 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrLiteralClassType.java @@ -135,22 +135,12 @@ public abstract class GrLiteralClassType extends PsiClassType { return type == null ? CommonClassNames.JAVA_LANG_OBJECT : type.getInternalCanonicalText(); } - @Nullable - private static PsiType getLeastUpperBound(@Nullable PsiType result, @Nullable PsiType other, PsiManager manager) { - if (other == null) return result; - if (result == null) result = other; - if (result.isAssignableFrom(other)) return result; - if (other.isAssignableFrom(result)) result = other; - - return TypesUtil.getLeastUpperBound(result, other, manager); - } - @NotNull protected PsiType getLeastUpperBound(PsiType[] psiTypes) { PsiType result = null; final PsiManager manager = getPsiManager(); for (final PsiType other : psiTypes) { - result = getLeastUpperBound(result, other, manager); + result = TypesUtil.getLeastUpperBoundNullable(result, other, manager); } return result == null ? PsiType.getJavaLangObject(manager, getResolveScope()) : result; } 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 f29b2b3fe11d..8639320aa778 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 @@ -398,6 +398,15 @@ public class TypesUtil { return PsiType.getJavaLangObject(context.getManager(), context.getResolveScope()); } + @Nullable + public static PsiType getLeastUpperBoundNullable(@Nullable PsiType type1, @Nullable PsiType type2, PsiManager manager) { + if (type1 == null) return type2; + if (type2 == null) return type1; + if (type1.isAssignableFrom(type2)) return type1; + if (type2.isAssignableFrom(type1)) return type2; + return getLeastUpperBound(type1, type2, manager); + } + @Nullable public static PsiType getLeastUpperBound(@NotNull PsiType type1, @NotNull PsiType type2, PsiManager manager) { if (type1 instanceof GrTupleType && type2 instanceof GrTupleType) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 149d746351cf..7900660e67b7 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -28,6 +28,7 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; @@ -51,6 +52,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; @@ -964,4 +967,40 @@ public class PsiUtil { } } + public static List collectReturns(PsiElement element) { + class ArrayListConsumer extends ArrayList implements Consumer { + + @Override + public void consume(GrReturnStatement grReturnStatement) { + add(grReturnStatement); + } + } + ArrayListConsumer res = new ArrayListConsumer(); + collectReturns(element, res); + + return res; + } + + public static void collectReturns(PsiElement element, Consumer consumer) { + if (element instanceof GrReturnStatement) { + consumer.consume((GrReturnStatement) element); + } else { + PsiElement child = element.getFirstChild(); + while(child != null) { + collectReturns(child, consumer); + child = child.getNextSibling(); + } + } + } + + @Nullable + public static GrStatement getLastStatement(@NotNull GrCodeBlock block) { + for (PsiElement element = block.getLastChild(); element != null; element = element.getPrevSibling()) { + if (element instanceof GrStatement) { + return (GrStatement)element; + } + } + + return null; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MethodTypeInferencer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MethodTypeInferencer.java index 32ac9adf669b..d3bd49929644 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MethodTypeInferencer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/MethodTypeInferencer.java @@ -23,6 +23,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.ArrayList; import java.util.List; @@ -39,51 +40,27 @@ public class MethodTypeInferencer implements Computable { @Nullable public PsiType compute () { - List returns = new ArrayList(); - collectReturns(myBlock, returns); + List returns = PsiUtil.collectReturns(myBlock); PsiType result = null; PsiManager manager = myBlock.getManager(); for (GrReturnStatement returnStatement : returns) { GrExpression value = returnStatement.getReturnValue(); if (value != null) { - result = upperBound(result, value.getType(), manager); + result = TypesUtil.getLeastUpperBoundNullable(result, value.getType(), manager); } } boolean isObject = returns.size() == 0; - GrStatement[] statements = myBlock.getStatements(); - if (statements.length > 0) { - GrStatement last = statements[statements.length - 1]; - if (last instanceof GrExpression) { - result = upperBound(((GrExpression) last).getType(), result, manager); - isObject = false; - } + GrStatement last = PsiUtil.getLastStatement(myBlock); + if (last instanceof GrExpression) { + result = TypesUtil.getLeastUpperBoundNullable(((GrExpression) last).getType(), result, manager); + isObject = false; } if (isObject) return TypesUtil.getJavaLangObject(myBlock); return result; } - - private static PsiType upperBound(PsiType type1, PsiType type2, PsiManager manager) { - if (type1 == null) return type2; - if (type2 == null) return type1; - if (type1.isAssignableFrom(type2)) return type1; - if (type2.isAssignableFrom(type1)) return type2; - return TypesUtil.getLeastUpperBound(type1, type2, manager); - } - - private static void collectReturns(PsiElement element, List returns) { - if (element instanceof GrReturnStatement) { - returns.add((GrReturnStatement) element); - } else { - PsiElement child = element.getFirstChild(); - while(child != null) { - collectReturns(child, returns); - child = child.getNextSibling(); - } - } - } }