dig deeper than one level in retrieving chained constructor calls' throws lists ...
authorpeter <peter.gromov@jetbrains.com>
Mon, 26 Apr 2010 13:57:30 +0000 (14:57 +0100)
committerpeter <peter.gromov@jetbrains.com>
Mon, 26 Apr 2010 14:37:27 +0000 (15:37 +0100)
plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java
plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java
plugins/groovy/testdata/groovy/stubGenerator/checkedExceptionInConstructorDelegate.test [new file with mode: 0644]
plugins/groovy/testdata/groovy/stubGenerator/superInvocation1.test

index ad781fc230cbac9e8af918c1b964a0c7c2db8a52..2a0cac487203e1a7705aed960b21d7401a6f4381 100644 (file)
@@ -35,6 +35,7 @@ import com.intellij.psi.*;
 import com.intellij.psi.util.MethodSignature;
 import com.intellij.psi.util.MethodSignatureUtil;
 import com.intellij.util.ArrayUtil;
+import com.intellij.util.containers.CollectionFactory;
 import com.intellij.util.containers.HashSet;
 import gnu.trove.THashSet;
 import org.jetbrains.annotations.NotNull;
@@ -487,7 +488,7 @@ public class GroovyToJavaGenerator {
     }
   }
 
-  private void writeEnumConstants(StringBuffer text, GrEnumTypeDefinition enumDefinition) {
+  private static void writeEnumConstants(StringBuffer text, GrEnumTypeDefinition enumDefinition) {
     text.append("\n  ");
     GrEnumConstant[] enumConstants = enumDefinition.getEnumConstants();
     for (int i = 0; i < enumConstants.length; i++) {
@@ -559,68 +560,76 @@ public class GroovyToJavaGenerator {
 
     text.append(") ");
 
+    final Set<String> throwsTypes = collectThrowsTypes(constructor);
+    if (!throwsTypes.isEmpty()) {
+      text.append("throws ").append(StringUtil.join(throwsTypes, ", ")).append(" ");
+    }
+
     /************* body **********/
 
-    final GrConstructorInvocation constructorInvocation = constructor.getChainingConstructorInvocation();
-    if (constructorInvocation != null) {
-      ApplicationManager.getApplication().runReadAction(new Runnable() {
-        public void run() {
-          GroovyResolveResult resolveResult = constructorInvocation.resolveConstructorGenerics();
-          PsiSubstitutor substitutor = resolveResult.getSubstitutor();
-          PsiMethod chainedConstructor = (PsiMethod) resolveResult.getElement();
-          if (chainedConstructor == null) {
-            final GroovyResolveResult[] results = constructorInvocation.multiResolveConstructor();
-            if (results.length > 0) {
-              int i = 0;
-              while (results.length > i+1) {
-                final PsiMethod candidate = (PsiMethod)results[i].getElement();
-                final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(constructor.getProject()).getResolveHelper();
-                if (candidate != null && candidate != constructor && resolveHelper.isAccessible(candidate, constructorInvocation, null)) {
-                  break;
-                }
-                i++;
-              }
-              chainedConstructor = (PsiMethod) results[i].getElement();
-              substitutor = results[i].getSubstitutor();
-            }
-          }
+    text.append("{\n");
+    final GrConstructorInvocation invocation = constructor.getChainingConstructorInvocation();
+    if (invocation != null) {
+      final GroovyResolveResult resolveResult = resolveChainingConstructor(constructor);
+      if (resolveResult != null) {
+        text.append("    ");
+        text.append(invocation.isSuperCall() ? "super(" : "this(");
+        writeStubConstructorInvocation(text, (PsiMethod) resolveResult.getElement(), resolveResult.getSubstitutor());
+        text.append(");");
+      }
+    }
 
-          if (chainedConstructor != null) {
-            final PsiClassType[] throwsTypes = chainedConstructor.getThrowsList().getReferencedTypes();
-            if (throwsTypes.length > 0) {
-              text.append(" throws ");
-              for (int i = 0; i < throwsTypes.length; i++) {
-                if (i > 0) text.append(", ");
-                text.append(getTypeText(substitutor.substitute(throwsTypes[i]), false));
-              }
-            }
-          }
+    text.append("\n  }\n");
+  }
 
-          text.append("{\n");
+  private static Set<String> collectThrowsTypes(GrConstructor constructor) {
+    final GroovyResolveResult resolveResult = resolveChainingConstructor(constructor);
+    if (resolveResult == null) {
+      return Collections.emptySet();
+    }
 
-          text.append("    ");
-          if (constructorInvocation.isSuperCall()) {
-            text.append("super");
-          } else {
-            text.append("this");
-          }
-          text.append("(");
+    final Set<String> result = CollectionFactory.newTroveSet();
 
-          if (chainedConstructor != null) {
-            writeStubConstructorInvocation(text, chainedConstructor, substitutor);
-          }
+    final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
+    final PsiMethod chainedConstructor = (PsiMethod)resolveResult.getElement();
+    assert chainedConstructor != null;
 
-          text.append(")");
-          text.append(";");
-        }
-      });
+    for (PsiClassType type : chainedConstructor.getThrowsList().getReferencedTypes()) {
+      result.add(getTypeText(substitutor.substitute(type), false));
+    }
 
-    } else {
-      text.append("{\n");
+    if (chainedConstructor instanceof GrConstructor) {
+      result.addAll(collectThrowsTypes((GrConstructor)chainedConstructor));
     }
+    return result;
+  }
 
-    text.append("\n  }");
-    text.append("\n");
+  @Nullable
+  private static GroovyResolveResult resolveChainingConstructor(GrConstructor constructor) {
+    final GrConstructorInvocation constructorInvocation = constructor.getChainingConstructorInvocation();
+    if (constructorInvocation == null) {
+      return null;
+    }
+
+    GroovyResolveResult resolveResult = constructorInvocation.resolveConstructorGenerics();
+    if (resolveResult.getElement() != null) {
+      return resolveResult;
+    }
+
+    final GroovyResolveResult[] results = constructorInvocation.multiResolveConstructor();
+    if (results.length > 0) {
+      int i = 0;
+      while (results.length > i+1) {
+        final PsiMethod candidate = (PsiMethod)results[i].getElement();
+        final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(constructor.getProject()).getResolveHelper();
+        if (candidate != null && candidate != constructor && resolveHelper.isAccessible(candidate, constructorInvocation, null)) {
+          break;
+        }
+        i++;
+      }
+      return results[i];
+    }
+    return null;
   }
 
   private static String getDefaultValueText(String typeCanonicalText) {
index ef433f0bd0eaad0885a830ab3b340a8fec84a142..0a2b63a25f6a027566cf77f0cad2dc92ea154a41 100644 (file)
@@ -60,6 +60,15 @@ public void testArrayType1() throws Throwable { doTest(); }
   public void testToGenerate1() throws Throwable { doTest(); }
   public void testVararg1() throws Throwable { doTest(); }
   public void testInaccessibleConstructor() throws Throwable { doTest(); }
+
+  public void testCheckedExceptionInConstructorDelegate() throws Throwable {
+    myFixture.addClass("package foo;" +
+                       "public class SuperClass {" +
+                       "  public SuperClass(String s) throws java.io.IOException {}" +
+                       "}");
+    doTest();
+  }
+
   public void testImmutableAnno() throws Throwable {
     myFixture.addClass("package groovy.lang; public @interface Immutable {}");
     doTest();
diff --git a/plugins/groovy/testdata/groovy/stubGenerator/checkedExceptionInConstructorDelegate.test b/plugins/groovy/testdata/groovy/stubGenerator/checkedExceptionInConstructorDelegate.test
new file mode 100644 (file)
index 0000000..74c9135
--- /dev/null
@@ -0,0 +1,40 @@
+class Foo extends foo.SuperClass {
+  protected Foo(Foo p) {
+    this("");
+  }
+  protected Foo(String s) {
+    super(s);
+  }
+}
+
+-----
+public class Foo extends foo.SuperClass implements groovy.lang.GroovyObject {
+  public Foo(Foo p) throws java.io.IOException {
+    this((java.lang.String)null);
+  }
+
+  public Foo(java.lang.String s) throws java.io.IOException {
+    super((java.lang.String)null);
+  }
+
+  public groovy.lang.MetaClass getMetaClass() {
+    return null;
+  }
+
+  public void setMetaClass(groovy.lang.MetaClass mc) {
+    return ;
+  }
+
+  public java.lang.Object invokeMethod(java.lang.String name, java.lang.Object args) {
+    return null;
+  }
+
+  public java.lang.Object getProperty(java.lang.String propertyName) {
+    return null;
+  }
+
+  public void setProperty(java.lang.String propertyName, java.lang.Object newValue) {
+    return ;
+  }
+}
+---
index be15d47c67bb6e5601f3a9a92d53adb7774c9709..5904bf95000579b6ee1e81491e31c2c6ac0df9ef 100644 (file)
@@ -35,7 +35,7 @@ public class Base implements groovy.lang.GroovyObject {
 }
 ---
 public class Derived extends Base implements groovy.lang.GroovyObject {
-  public Derived()  throws java.lang.Exception{
+  public Derived() throws java.lang.Exception {
     super((java.lang.String)null, (int)0);
   }