From acf850e254ab2d802dac0fd5dca27aba605ad64b Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Mon, 9 Jun 2014 19:51:31 +0400 Subject: [PATCH] IDEA-126013 fix SOE : maps and lists declared recursively should not fail type inference into recursion --- .../groovy/lang/psi/impl/GrMapType.java | 5 ++++ .../lang/psi/impl/GrMapTypeFromNamedArgs.java | 24 ++++++++++++++----- .../psi/impl/auxiliary/GrListOrMapImpl.java | 11 +++++++-- .../statements/expressions/TypesUtil.java | 2 +- .../lang/resolve/TypeInferenceTest.groovy | 18 ++++++++++++++ 5 files changed, 51 insertions(+), 9 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java index 51022367d830..b9d4cf0ad6f7 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java @@ -183,4 +183,9 @@ public abstract class GrMapType extends GrLiteralClassType { public static GrMapType createFromNamedArgs(PsiElement context, GrNamedArgument[] args) { return new GrMapTypeFromNamedArgs(context, args); } + + @Override + public String toString() { + return "map type"; + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java index fdc8fa434e3d..6159aee951f1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapTypeFromNamedArgs.java @@ -15,7 +15,9 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.RecursionManager; import com.intellij.openapi.util.VolatileNotNullLazyValue; import com.intellij.psi.CommonClassNames; import com.intellij.psi.JavaPsiFacade; @@ -50,7 +52,7 @@ public class GrMapTypeFromNamedArgs extends GrMapType { return ContainerUtil.map(myOtherEntries, new Function, Couple>() { @Override public Couple fun(Couple pair) { - return Couple.of(pair.first.getType(), pair.second.getType()); + return Couple.of(inferTypePreventingRecursion(pair.first), inferTypePreventingRecursion(pair.second)); } }); } @@ -62,7 +64,7 @@ public class GrMapTypeFromNamedArgs extends GrMapType { protected Map compute() { HashMap result = ContainerUtil.newHashMap(); for (Map.Entry entry : myStringEntries.entrySet()) { - result.put(entry.getKey(), entry.getValue().getType()); + result.put(entry.getKey(), inferTypePreventingRecursion(entry.getValue())); } return result; } @@ -99,7 +101,7 @@ public class GrMapTypeFromNamedArgs extends GrMapType { @Override public PsiType getTypeByStringKey(String key) { GrExpression expression = myStringEntries.get(key); - return expression != null ? expression.getType() : null; + return expression != null ? inferTypePreventingRecursion(expression) : null; } @NotNull @@ -121,7 +123,7 @@ public class GrMapTypeFromNamedArgs extends GrMapType { result.add(GroovyPsiManager.getInstance(myFacade.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, getResolveScope())); } for (Couple entry : myOtherEntries) { - result.add(entry.first.getType()); + result.add(inferTypePreventingRecursion(entry.first)); } result.remove(null); return result.toArray(createArray(result.size())); @@ -132,15 +134,25 @@ public class GrMapTypeFromNamedArgs extends GrMapType { protected PsiType[] getAllValueTypes() { Set result = ContainerUtil.newHashSet(); for (GrExpression expression : myStringEntries.values()) { - result.add(expression.getType()); + result.add(inferTypePreventingRecursion(expression)); } for (Couple entry : myOtherEntries) { - result.add(entry.second.getType()); + result.add(inferTypePreventingRecursion(entry.second)); } result.remove(null); return result.toArray(createArray(result.size())); } + @Nullable + private static PsiType inferTypePreventingRecursion(final GrExpression expression) { + return RecursionManager.doPreventingRecursion(expression, false, new Computable() { + @Override + public PsiType compute() { + return expression.getType(); + } + }); + } + @NotNull @Override protected List> getOtherEntries() { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java index 0ad33ee29752..952f04877092 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/auxiliary/GrListOrMapImpl.java @@ -17,6 +17,8 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary; import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.search.GlobalSearchScope; @@ -215,8 +217,13 @@ public class GrListOrMapImpl extends GrExpressionImpl implements GrListOrMap { protected PsiType[] inferComponents() { return ContainerUtil.map(initializers, new Function() { @Override - public PsiType fun(GrExpression expression) { - return expression.getType(); + public PsiType fun(final GrExpression expression) { + return RecursionManager.doPreventingRecursion(expression, false, new Computable() { + @Override + public PsiType compute() { + return expression.getType(); + } + }); } }, new PsiType[initializers.length]); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java index 81d0ce903e4a..f5d4877274a0 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java @@ -747,7 +747,7 @@ public class TypesUtil { } @Nullable - public static PsiType inferAnnotationMemberValueType(GrAnnotationMemberValue value) { + public static PsiType inferAnnotationMemberValueType(final GrAnnotationMemberValue value) { if (value instanceof GrExpression) { return ((GrExpression)value).getType(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy index f02b94000714..40173b3ee230 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy @@ -696,4 +696,22 @@ class Any { doExprTest('1f/2.4', 'java.lang.Double') } + void testRecursionWithMaps() { + doTest(''' +def foo(Map map) { + while(true) + map = [a:map] +} +''', 'java.util.Map') + } + + void testRecursionWithLists() { + doTest(''' +def foo(List list) { + while(true) + list = [list] +} +''', 'java.util.ArrayList') + } + }