diff --git a/plugins/groovy/groovypp/groovypp.iml b/plugins/groovy/groovypp/groovypp.iml
index e5156fdc12ec..c80576200148 100644
--- a/plugins/groovy/groovypp/groovypp.iml
+++ b/plugins/groovy/groovypp/groovypp.iml
@@ -11,6 +11,7 @@
+
diff --git a/plugins/groovy/groovypp/src/META-INF/plugin.xml b/plugins/groovy/groovypp/src/META-INF/plugin.xml
index 70895af0ab7e..9358b1c52fc4 100644
--- a/plugins/groovy/groovypp/src/META-INF/plugin.xml
+++ b/plugins/groovy/groovypp/src/META-INF/plugin.xml
@@ -3,13 +3,14 @@
Groovy++ Support
Adds code assistance for the Groovy++ features
0.1
-
+
JetBrains Inc.
org.intellij.groovy
+
diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java
index 98cd311bf484..7a9548292da7 100644
--- a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java
+++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java
@@ -10,13 +10,14 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.AbstractClosureParameterEnhancer;
+import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
-import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
+import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
import java.util.*;
@@ -40,7 +41,37 @@ public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnh
return null;
}
- for (PsiType constraint : getExpectedTypes(closure)) {
+ final PsiElement parent = closure.getParent();
+ if (parent instanceof GrListOrMap) {
+ final GrListOrMap list = (GrListOrMap)parent;
+ if (!list.isMap()) {
+ final PsiType listType = list.getType();
+ final int argIndex = Arrays.asList(list.getInitializers()).indexOf(closure);
+ assert argIndex >= 0;
+ if (listType instanceof GrTupleType) {
+ for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(list)) {
+ if (type instanceof PsiClassType) {
+ for (GroovyResolveResult resolveResult : GppTypeConverter
+ .getConstructorCandidates((PsiClassType)type, ((GrTupleType)listType).getComponentTypes(), closure)) {
+ final PsiElement method = resolveResult.getElement();
+ if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) {
+ final PsiType toCastTo =
+ resolveResult.getSubstitutor().substitute(((PsiMethod)method).getParameterList().getParameters()[argIndex].getType());
+ final PsiType suggestion = getSingleMethodParameterType(toCastTo, index, closure);
+ if (suggestion != null) {
+ return suggestion;
+ }
+ }
+
+ }
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ for (PsiType constraint : GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure)) {
final PsiType suggestion = getSingleMethodParameterType(constraint, index, closure);
if (suggestion != null) {
return suggestion;
@@ -49,14 +80,6 @@ public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnh
return null;
}
- private static Set getExpectedTypes(GrExpression element) {
- final LinkedHashSet result = new LinkedHashSet();
- for (TypeConstraint constraint : GroovyExpectedTypesProvider.calculateTypeConstraints(element)) {
- result.add(constraint.getDefaultType());
- }
- return result;
- }
-
@Nullable
private static Pair getOverriddenMethod(GrClosableBlock closure) {
final PsiElement parent = closure.getParent();
@@ -76,7 +99,7 @@ public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnh
final PsiElement map = parent.getParent();
if (map instanceof GrListOrMap && ((GrListOrMap)map).isMap()) {
- for (PsiType expected : getExpectedTypes((GrExpression)map)) {
+ for (PsiType expected : GroovyExpectedTypesProvider.getDefaultExpectedTypes((GrExpression)map)) {
if (expected instanceof PsiClassType) {
final List> pairs = getMethodsToOverrideImplementInInheritor((PsiClassType)expected, false);
final List> withName =
diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java
new file mode 100644
index 000000000000..0c97a5c4beb6
--- /dev/null
+++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppExpectedTypesContributor.java
@@ -0,0 +1,69 @@
+package org.jetbrains.plugins.groovy.gpp;
+
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
+import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesContributor;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SubtypeConstraint;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
+import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author peter
+ */
+public class GppExpectedTypesContributor extends GroovyExpectedTypesContributor {
+ @Override
+ public List calculateTypeConstraints(@NotNull GrExpression expression) {
+ if (!GppTypeConverter.hasTypedContext(expression)) {
+ return Collections.emptyList();
+ }
+
+ final PsiElement parent = expression.getParent();
+ if (parent instanceof GrListOrMap) {
+ final GrListOrMap list = (GrListOrMap)parent;
+ if (!list.isMap()) {
+ return addExpectedConstructorParameters(expression, list);
+ }
+ else {
+ //todo expected property types
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private static List addExpectedConstructorParameters(GrExpression expression, GrListOrMap list) {
+ final PsiType listType = list.getType();
+ if (!(listType instanceof GrTupleType)) {
+ return Collections.emptyList();
+ }
+
+ final PsiType[] argTypes = ((GrTupleType)listType).getComponentTypes();
+ final int argIndex = Arrays.asList(list.getInitializers()).indexOf(expression);
+ assert argIndex >= 0;
+
+ final ArrayList result = new ArrayList();
+ for (PsiType type : GroovyExpectedTypesProvider.getDefaultExpectedTypes(expression)) {
+ if (type instanceof PsiClassType) {
+ for (GroovyResolveResult resolveResult : GppTypeConverter.getConstructorCandidates((PsiClassType)type, argTypes, expression)) {
+ final PsiElement method = resolveResult.getElement();
+ if (method instanceof PsiMethod && ((PsiMethod)method).isConstructor()) {
+ final PsiParameter[] constructorParameters = ((PsiMethod)method).getParameterList().getParameters();
+ if (constructorParameters.length > argIndex) {
+ final PsiType toCastTo = resolveResult.getSubstitutor().substitute(constructorParameters[argIndex].getType());
+ result.add(SubtypeConstraint.create(toCastTo));
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java
index 55d0f53079c6..ba7972af432b 100644
--- a/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java
+++ b/plugins/groovy/groovypp/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java
@@ -105,19 +105,21 @@ public class GppTypeConverter extends GrTypeConverter {
}
private static boolean hasConstructor(PsiClassType lType, PsiType[] argTypes, GroovyPsiElement context) {
- final PsiClassType.ClassResolveResult resolveResult = lType.resolveGenerics();
+ return getConstructorCandidates(lType, argTypes, context).length == 1;
+ }
+
+ public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) {
+ final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (psiClass == null) {
- return false;
+ return GroovyResolveResult.EMPTY_ARRAY;
}
final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult
? (GroovyResolveResult)resolveResult
: new GroovyResolveResultImpl(psiClass, context, substitutor, true, true);
- final GroovyResolveResult[] candidates = org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates(
- context, new GroovyResolveResult[]{grResult}, argTypes);
- return candidates.length == 1;
+ return org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes);
}
}
diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml
index 53fa86c3cf2c..7848c88e19bf 100644
--- a/plugins/groovy/src/META-INF/plugin.xml
+++ b/plugins/groovy/src/META-INF/plugin.xml
@@ -32,6 +32,7 @@
+
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesContributor.java
new file mode 100644
index 000000000000..5932d1e14357
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesContributor.java
@@ -0,0 +1,16 @@
+package org.jetbrains.plugins.groovy.lang.psi.expectedTypes;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+
+import java.util.List;
+
+/**
+ * @author peter
+ */
+public abstract class GroovyExpectedTypesContributor {
+ public static final ExtensionPointName EP_NAME = ExtensionPointName.create("org.intellij.groovy.expectedTypesContributor");
+
+ public abstract List calculateTypeConstraints(@NotNull GrExpression expression);
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java
index 41d04fdc276a..8e6af987e71b 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java
@@ -38,9 +38,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.*;
/**
* @author ven
@@ -52,7 +50,27 @@ public class GroovyExpectedTypesProvider {
public static TypeConstraint[] calculateTypeConstraints(GrExpression expression) {
MyCalculator calculator = new MyCalculator(expression);
((GroovyPsiElement)expression.getParent()).accept(calculator);
- return calculator.getResult();
+ final TypeConstraint[] result = calculator.getResult();
+
+ List custom = new ArrayList();
+ for (GroovyExpectedTypesContributor contributor : GroovyExpectedTypesContributor.EP_NAME.getExtensions()) {
+ custom.addAll(contributor.calculateTypeConstraints(expression));
+ }
+
+ if (!custom.isEmpty()) {
+ custom.addAll(0, Arrays.asList(result));
+ return custom.toArray(new TypeConstraint[custom.size()]);
+ }
+
+ return result;
+ }
+
+ public static Set getDefaultExpectedTypes(GrExpression element) {
+ final LinkedHashSet result = new LinkedHashSet();
+ for (TypeConstraint constraint : calculateTypeConstraints(element)) {
+ result.add(constraint.getDefaultType());
+ }
+ return result;
}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy
index c639aa230e5a..3ed1eda224fc 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy
@@ -235,6 +235,20 @@ class Foo {
@Typed Foo bar() {
return [foo: { it.subs }]
}
+"""
+ myFixture.completeBasic()
+ assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
+ }
+
+ public void testClosureInListInstantiation() throws Exception {
+ myFixture.configureByText "a.groovy", """
+class Foo {
+ def Foo(int a, Function1 f) {}
+}
+
+@Typed Foo foo() {
+ [239, { s -> s.subs }]
+}
"""
myFixture.completeBasic()
assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"