fixing possible stack overflow in case of a cyclic constructor invocation in groovy...
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / compiler / generator / GroovyToJavaGenerator.java
index a13aeb826140bd03b8a2ada3b0b1c7cfb598bbb4..19749946b1b527c84aff9cfb7c0efdc006d10b0b 100644 (file)
@@ -559,7 +559,7 @@ public class GroovyToJavaGenerator {
 
     text.append(") ");
 
-    final Set<String> throwsTypes = collectThrowsTypes(constructor);
+    final Set<String> throwsTypes = collectThrowsTypes(constructor, new THashSet<PsiMethod>());
     if (!throwsTypes.isEmpty()) {
       text.append("throws ").append(StringUtil.join(throwsTypes, ", ")).append(" ");
     }
@@ -581,24 +581,28 @@ public class GroovyToJavaGenerator {
     text.append("\n  }\n");
   }
 
-  private static Set<String> collectThrowsTypes(GrConstructor constructor) {
+  private static Set<String> collectThrowsTypes(GrConstructor constructor, Set<PsiMethod> visited) {
     final GroovyResolveResult resolveResult = resolveChainingConstructor(constructor);
     if (resolveResult == null) {
       return Collections.emptySet();
     }
 
-    final Set<String> result = CollectionFactory.newTroveSet();
 
     final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
     final PsiMethod chainedConstructor = (PsiMethod)resolveResult.getElement();
     assert chainedConstructor != null;
 
+    if (!visited.add(chainedConstructor)) {
+      return Collections.emptySet();
+    }
+
+    final Set<String> result = CollectionFactory.newTroveSet();
     for (PsiClassType type : chainedConstructor.getThrowsList().getReferencedTypes()) {
       result.add(getTypeText(substitutor.substitute(type), null, false));
     }
 
     if (chainedConstructor instanceof GrConstructor) {
-      result.addAll(collectThrowsTypes((GrConstructor)chainedConstructor));
+      result.addAll(collectThrowsTypes((GrConstructor)chainedConstructor, visited));
     }
     return result;
   }