diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml
index 8b085b2dd8cf..1931ece2bfdf 100644
--- a/plugins/groovy/src/META-INF/plugin.xml
+++ b/plugins/groovy/src/META-INF/plugin.xml
@@ -51,6 +51,7 @@
+
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
index 5db12cf6ed1c..8f6005b61cb6 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
@@ -91,6 +91,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
+import org.jetbrains.plugins.groovy.lang.resolve.noncode.GrInheritConstructorContributor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
import org.jetbrains.plugins.groovy.overrideImplement.GroovyOverrideImplementUtil;
import org.jetbrains.plugins.groovy.overrideImplement.quickFix.ImplementMethodsQuickFix;
@@ -289,6 +290,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
final PsiClass superClass = typeDefinition.getSuperClass();
if (superClass == null) return;
+ if (GrInheritConstructorContributor.hasInheritConstructorsAnnotation(typeDefinition)) return;
+
PsiMethod defConstructor = getDefaultConstructor(superClass);
boolean hasImplicitDefConstructor = superClass.getConstructors().length ==0;
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java
index f09e23bc2fd7..1293b1b7f8f8 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
@@ -48,6 +49,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClassTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
+import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.*;
@@ -287,7 +289,14 @@ public class GroovyCompletionUtil {
}
public static boolean hasConstructorParameters(PsiClass clazz) {
- final PsiMethod[] constructors = clazz.getConstructors();
+ final PsiMethod[] constructors;
+ if (clazz instanceof GroovyPsiElement) {
+ constructors = ResolveUtil.getAllClassConstructors(clazz, (GroovyPsiElement)clazz, PsiSubstitutor.EMPTY);
+ }
+ else {
+ constructors = clazz.getConstructors();
+ }
+
for (PsiMethod constructor : constructors) {
if (constructor.getParameterList().getParametersCount() > 0) return true;
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java
index ddf5d564bd12..ffe728bd3e7f 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java
@@ -30,6 +30,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
@@ -37,6 +38,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
+import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import java.util.Arrays;
@@ -114,7 +116,7 @@ public class GroovyInsertHandler implements InsertHandler {
parent.getParent() instanceof GrNewExpression &&
(offset == text.length() || !text.substring(offset).trim().startsWith("("))) {
document.insertString(offset, "()");
- final PsiMethod[] methods = clazz.getConstructors();
+ final PsiMethod[] methods = ResolveUtil.getAllClassConstructors(clazz, (GroovyPsiElement)parent, PsiSubstitutor.EMPTY);
for (PsiMethod method : methods) {
if (method.getParameterList().getParameters().length > 0) {
caretModel.moveToOffset(offset + 1);
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/handlers/AfterNewClassInsertHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/handlers/AfterNewClassInsertHandler.java
index b4006fe9c70e..58c5e4c43d49 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/handlers/AfterNewClassInsertHandler.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/handlers/AfterNewClassInsertHandler.java
@@ -28,11 +28,12 @@ import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
-import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
+import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
+import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
/**
* @author Maxim.Medvedev
@@ -47,13 +48,16 @@ public class AfterNewClassInsertHandler implements InsertHandler item) {
- final PsiClass psiClass = PsiUtil.resolveClassInType(myClassType);
+ final PsiClassType.ClassResolveResult resolveResult = myClassType.resolveGenerics();
+ final PsiClass psiClass = resolveResult.getElement();
if (psiClass == null || !psiClass.isValid()) {
return;
}
-
-
- PsiMethod[] constructors = psiClass.getConstructors();
+ PsiElement place = myPlace;
+ if (!(place instanceof GroovyPsiElement)) {
+ place = myPlace.getContainingFile();
+ }
+ PsiMethod[] constructors = ResolveUtil.getAllClassConstructors(psiClass, (GroovyPsiElement)place, resolveResult.getSubstitutor());
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(psiClass.getProject()).getResolveHelper();
boolean hasParams = ContainerUtil.or(constructors, new Condition() {
public boolean value(PsiMethod psiMethod) {
@@ -151,8 +155,8 @@ public class AfterNewClassInsertHandler implements InsertHandler(args[i]);
}
for (int i = 0; i < map.length; i++) {
@@ -222,7 +222,7 @@ public class GrClosureSignatureUtil {
if (curParam == paramLength) break;
if (params[curParam].isOptional()) {
- if (TypesUtil.isAssignable(params[curParam].getType(), types[curArg], context, false) &&
+ if (TypesUtil.isAssignableByMethodCallConversion(params[curParam].getType(), types[curArg], context) &&
isApplicableInternal(curParam + 1, curArg + 1, false, notOptional)) {
map[curParam] = new ArgInfo(args[curArg]);
return true;
@@ -230,7 +230,7 @@ public class GrClosureSignatureUtil {
skipOptionals = true;
}
else {
- if (!TypesUtil.isAssignable(params[curParam].getType(), types[curArg], context, false)) {
+ if (!TypesUtil.isAssignableByMethodCallConversion(params[curParam].getType(), types[curArg], context)) {
for (int i = startParam; i < curParam; i++) map[i] = null;
return false;
}
@@ -243,7 +243,7 @@ public class GrClosureSignatureUtil {
List varargs = new ArrayList();
for (; curArg < args.length; curArg++) {
- if (!TypesUtil.isAssignable(vararg, types[curArg], context, false)) {
+ if (!TypesUtil.isAssignableByMethodCallConversion(vararg, types[curArg], context)) {
for (int i = startParam; i < curParam; i++) map[i] = null;
return false;
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java
index da740a065bdf..b1308def84aa 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java
@@ -51,6 +51,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGd
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor;
+import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
@@ -503,4 +504,27 @@ public class ResolveUtil {
}
return variants;
}
+
+ public static GroovyResolveResult[] getNonCodeConstructors(PsiClass psiClass, GroovyPsiElement place, PsiSubstitutor substitutor) {
+ final PsiClassType qualifierType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass);
+ final MethodResolverProcessor processor = new MethodResolverProcessor(psiClass.getName(), place, true, null, null, PsiType.EMPTY_ARRAY);
+ NonCodeMembersContributor
+ .runContributors(qualifierType, processor, place, ResolveState.initial().put(PsiSubstitutor.KEY, substitutor));
+ return processor.getCandidates();
+ }
+
+ public static PsiMethod[] getAllClassConstructors(PsiClass psiClass, GroovyPsiElement place, PsiSubstitutor substitutor) {
+ final PsiMethod[] realConstructors = psiClass.getConstructors();
+ final GroovyResolveResult[] nonCodeConstructors = getNonCodeConstructors(psiClass, place, substitutor);
+ PsiMethod[] constructors = new PsiMethod[realConstructors.length + nonCodeConstructors.length];
+ System.arraycopy(realConstructors, 0, constructors, 0, realConstructors.length);
+ for (int i = 0; i < nonCodeConstructors.length; i++) {
+ GroovyResolveResult nonCodeConstructor = nonCodeConstructors[i];
+ final PsiElement element = nonCodeConstructor.getElement();
+ if (element instanceof PsiMethod) {
+ constructors[i + realConstructors.length] = (PsiMethod)element;
+ }
+ }
+ return constructors;
+ }
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/GrInheritConstructorContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/GrInheritConstructorContributor.java
new file mode 100644
index 000000000000..cf2222a6c1e1
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/GrInheritConstructorContributor.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2010 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.noncode;
+
+import com.intellij.psi.*;
+import com.intellij.psi.scope.PsiScopeProcessor;
+import com.intellij.psi.util.TypeConversionUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class GrInheritConstructorContributor extends NonCodeMembersContributor {
+ public static final String INHERIT_CONSTRUCTOR_NAME = "groovy.transform.InheritConstructors";
+
+ @Override
+ public void processDynamicElements(@NotNull PsiType qualifierType, PsiScopeProcessor processor, PsiElement place, ResolveState state) {
+ if (!(qualifierType instanceof PsiClassType)) return;
+ final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)qualifierType).resolveGenerics();
+ final PsiClass psiClass = resolveResult.getElement();
+ if (!(psiClass instanceof GrTypeDefinition) ||
+ ((GrTypeDefinition)psiClass).isAnonymous() ||
+ psiClass.isInterface() ||
+ psiClass.isEnum()) {
+ return;
+ }
+
+ if (!hasInheritConstructorsAnnotation(psiClass)) return;
+
+ final PsiClass superClass = psiClass.getSuperClass();
+ if (superClass == null) return;
+ final PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
+ final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, psiClass, substitutor);
+ final ResolveState currentState = state.put(PsiSubstitutor.KEY, superClassSubstitutor);
+
+ final PsiMethod[] constructors = superClass.getConstructors();
+ for (PsiMethod constructor : constructors) {
+ if (!processor.execute(constructor, currentState)) return;
+ }
+ }
+
+ public static boolean hasInheritConstructorsAnnotation(PsiClass psiClass) {
+ final PsiModifierList modifierList = psiClass.getModifierList();
+ if (modifierList == null) return false;
+ final PsiAnnotation[] annotations = modifierList.getAnnotations();
+ boolean hasInheritConstructors = false;
+ for (PsiAnnotation annotation : annotations) {
+ if (INHERIT_CONSTRUCTOR_NAME.equals(annotation.getQualifiedName())) {
+ hasInheritConstructors = true;
+ break;
+ }
+ }
+ return hasInheritConstructors;
+ }
+}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java
index dda8d5055d00..d04ccbb008d8 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCompletionTest.java
@@ -293,4 +293,17 @@ public class GroovyCompletionTest extends LightCodeInsightFixtureTestCase {
public void testIncSmartCompletion() throws Exception {
doSmartCompletion("a", "b");
}
+
+ public void testInheritConstructorsAnnotation() throws Throwable {
+ myFixture.addFileToProject("groovy/transform/InheritConstructors.java", "package groovy.transform;\n" +
+ "\n" +
+ "import java.lang.annotation.ElementType;\n" +
+ "import java.lang.annotation.Retention;\n" +
+ "import java.lang.annotation.RetentionPolicy;\n" +
+ "import java.lang.annotation.Target;@Retention(RetentionPolicy.SOURCE)\n" +
+ "@Target({ElementType.TYPE})\n" +
+ "public @interface InheritConstructors {\n" +
+ "}");
+ doSmartTest();
+ }
}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy
index e05bdbc4687c..5c810d2e9378 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2010 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.gant;
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java
index b505e2061e5a..ccafebd38f7c 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java
@@ -270,4 +270,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
public void testSignatureIsNotApplicableToList() throws Exception {
doTest();
}
+
+ public void testInheritConstructorsAnnotation() throws Exception {
+ doTest();
+ }
}
\ No newline at end of file
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java
index d8ca5fd0c791..acd4c395d50a 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java
@@ -63,7 +63,7 @@ public abstract class TestUtils {
}
public static String getMockGroovy1_7LibraryName() {
- return getMockGroovy1_7LibraryHome()+"/groovy-all-1.7.jar";
+ return getMockGroovy1_7LibraryHome()+"/groovy-all-1.7.3.jar";
}
public static PsiFile createPseudoPhysicalGroovyFile(final Project project, final String text) throws IncorrectOperationException {
diff --git a/plugins/groovy/testdata/groovy/completion/InheritConstructorsAnnotation.groovy b/plugins/groovy/testdata/groovy/completion/InheritConstructorsAnnotation.groovy
new file mode 100644
index 000000000000..748ce3a69d4a
--- /dev/null
+++ b/plugins/groovy/testdata/groovy/completion/InheritConstructorsAnnotation.groovy
@@ -0,0 +1,12 @@
+import groovy.transform.InheritConstructors
+
+class Base {
+ def Base(Date x) {}
+}
+
+@InheritConstructors
+class Inheritor extends Base {
+
+}
+
+Inheritor i = new Inheri
\ No newline at end of file
diff --git a/plugins/groovy/testdata/groovy/completion/InheritConstructorsAnnotation_after.groovy b/plugins/groovy/testdata/groovy/completion/InheritConstructorsAnnotation_after.groovy
new file mode 100644
index 000000000000..a7712aa4ec28
--- /dev/null
+++ b/plugins/groovy/testdata/groovy/completion/InheritConstructorsAnnotation_after.groovy
@@ -0,0 +1,12 @@
+import groovy.transform.InheritConstructors
+
+class Base {
+ def Base(Date x) {}
+}
+
+@InheritConstructors
+class Inheritor extends Base {
+
+}
+
+Inheritor i = new Inheritor()
\ No newline at end of file
diff --git a/plugins/groovy/testdata/highlighting/InheritConstructorsAnnotation.groovy b/plugins/groovy/testdata/highlighting/InheritConstructorsAnnotation.groovy
new file mode 100644
index 000000000000..3683804d6205
--- /dev/null
+++ b/plugins/groovy/testdata/highlighting/InheritConstructorsAnnotation.groovy
@@ -0,0 +1,13 @@
+import groovy.transform.InheritConstructors
+
+class Base {
+ def Base(T x) {}
+}
+
+@InheritConstructors
+class Inheritor extends Base {
+
+}
+
+Inheritor i = new Inheritor(new Date())
+Inheritor i2 = new Inheritor(2)
diff --git a/plugins/groovy/testdata/mockGroovyLib1.7/groovy-all-1.7.3.jar b/plugins/groovy/testdata/mockGroovyLib1.7/groovy-all-1.7.3.jar
new file mode 100644
index 000000000000..4a628324cfa4
Binary files /dev/null and b/plugins/groovy/testdata/mockGroovyLib1.7/groovy-all-1.7.3.jar differ