diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml
index dbf606cb014a..0677ce7e72cf 100644
--- a/plugins/groovy/src/META-INF/plugin.xml
+++ b/plugins/groovy/src/META-INF/plugin.xml
@@ -540,6 +540,9 @@
+
+
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java
index bb8e0c33488e..8804c7459000 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java
@@ -209,11 +209,15 @@ public class GroovyPsiManager {
}
}
if (!type.isValid()) {
- LOG.error("Type is invalid: " + type + "; element: " + element + " of class " + element.getClass());
+ error(element, type);
}
return UNKNOWN_TYPE == type ? null : type;
}
+ private static void error(PsiElement element, PsiType type) {
+ LOG.error("Type is invalid: " + type + "; element: " + element + " of class " + element.getClass());
+ }
+
@Nullable
public GrTypeDefinition getArrayClass(@NotNull PsiType type) {
final String typeText = type.getCanonicalText();
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java
index dac07251e6c7..d77f5ec59d5c 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java
@@ -17,6 +17,7 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks;
import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.tree.IElementType;
@@ -49,6 +50,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterListImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.ClosureSyntheticParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightVariable;
+import org.jetbrains.plugins.groovy.lang.resolve.KnownRecursionManager;
import org.jetbrains.plugins.groovy.lang.resolve.MethodTypeInferencer;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
@@ -335,7 +337,12 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock
@Nullable
public PsiType getReturnType() {
- return TypeInferenceHelper.getCurrentContext().getExpressionType(this, ourTypesCalculator);
+ return KnownRecursionManager.getInstance().run(this, new Computable() {
+ @Override
+ public PsiType compute() {
+ return TypeInferenceHelper.getCurrentContext().getExpressionType(GrClosableBlockImpl.this, ourTypesCalculator);
+ }
+ }, getAllParameters());
}
@Override
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java
index f74185bbd5af..274b013371b9 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java
@@ -17,6 +17,7 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.params;
import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.search.LocalSearchScope;
@@ -48,6 +49,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrParameterStub;
import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer;
import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrVariableEnhancer;
+import org.jetbrains.plugins.groovy.lang.resolve.KnownRecursionManager;
/**
* @author: Dmitry.Krasilschikov
@@ -100,7 +102,12 @@ public class GrParameterImpl extends GrVariableBaseImpl impleme
return TypesUtil.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, this);
}
- return GrVariableEnhancer.getEnhancedType(this);
+ return KnownRecursionManager.getInstance().run(this, new Computable() {
+ @Override
+ public PsiType compute() {
+ return GrVariableEnhancer.getEnhancedType(GrParameterImpl.this);
+ }
+ }, getDeclarationScope());
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/KnownRecursionManager.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/KnownRecursionManager.java
new file mode 100644
index 000000000000..6542a315864a
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/KnownRecursionManager.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.groovy.lang.resolve;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.util.Computable;
+import com.intellij.util.containers.ContainerUtil;
+
+import java.util.Set;
+
+/**
+ * Created by Max Medvedev on 10/04/14
+ */
+public class KnownRecursionManager {
+ private final ThreadLocal myThreads = new ThreadLocal() {
+ @Override
+ protected ThreadInfo initialValue() {
+ return new ThreadInfo();
+ }
+ };
+
+ public T run(Object key, Computable computable, Object... stopAt) {
+ try {
+ if (!startInference(key, stopAt)) {
+ return null;
+ }
+ return computable.compute();
+ }
+ finally {
+ try {
+ finishInference(key);
+ }
+ catch (Throwable e) {
+ //noinspection ThrowFromFinallyBlock
+ throw new RuntimeException("exception in finishInference", e);
+ }
+ }
+ }
+
+ private boolean startInference(Object key, Object[] stopAt) {
+ ThreadInfo info = myThreads.get();
+
+ for (Object o : stopAt) {
+ if (info.myObjects.contains(o)) return false;
+ }
+ if (!info.myObjects.add(key)) return false;
+
+ return true;
+ }
+
+ private void finishInference(Object key) {
+ ThreadInfo info = myThreads.get();
+
+ info.myObjects.remove(key);
+ }
+
+ public static KnownRecursionManager getInstance() {
+ return ServiceManager.getService(KnownRecursionManager.class);
+ }
+
+ private static class ThreadInfo {
+ private final Set