recognize OMI when instatiating objects as list literals

This commit is contained in:
peter
2010-05-04 16:05:54 +01:00
parent 88f68cb015
commit fa6abf812a
9 changed files with 166 additions and 21 deletions
+1
View File
@@ -11,6 +11,7 @@
<orderEntry type="module" module-name="lang-api" />
<orderEntry type="module" module-name="idea-ui" />
<orderEntry type="module" module-name="openapi" />
<orderEntry type="module" module-name="java-impl" />
</component>
</module>
@@ -3,13 +3,14 @@
<name>Groovy++ Support</name>
<description>Adds code assistance for the Groovy++ features</description>
<version>0.1</version>
<idea-version since-build="95.90" until-build="96.1"/>
<idea-version since-build="95.90" until-build="96.239"/>
<vendor logo="/org/jetbrains/plugins/groovy/images/groovy_16x16.png" url="http://www.jetbrains.com">JetBrains Inc.</vendor>
<depends>org.intellij.groovy</depends>
<extensions defaultExtensionNs="org.intellij.groovy">
<libraryManager implementation="org.jetbrains.plugins.groovy.gpp.GppLibraryManager" order="first"/>
<typeConverter implementation="org.jetbrains.plugins.groovy.gpp.GppTypeConverter"/>
<expectedTypesContributor implementation="org.jetbrains.plugins.groovy.gpp.GppExpectedTypesContributor"/>
<variableEnhancer implementation="org.jetbrains.plugins.groovy.gpp.GppClosureParameterTypeProvider"/>
</extensions>
@@ -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<PsiType> getExpectedTypes(GrExpression element) {
final LinkedHashSet<PsiType> result = new LinkedHashSet<PsiType>();
for (TypeConstraint constraint : GroovyExpectedTypesProvider.calculateTypeConstraints(element)) {
result.add(constraint.getDefaultType());
}
return result;
}
@Nullable
private static Pair<PsiMethod, PsiSubstitutor> 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<Pair<PsiMethod, PsiSubstitutor>> pairs = getMethodsToOverrideImplementInInheritor((PsiClassType)expected, false);
final List<Pair<PsiMethod, PsiSubstitutor>> withName =
@@ -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<TypeConstraint> 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<TypeConstraint> 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<TypeConstraint> result = new ArrayList<TypeConstraint>();
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;
}
}
@@ -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);
}
}
+1
View File
@@ -32,6 +32,7 @@
<extensionPoint name="nonCodeProcessor" interface="org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor"/>
<extensionPoint name="variableEnhancer" interface="org.jetbrains.plugins.groovy.lang.psi.GrVariableEnhancer"/>
<extensionPoint name="typeConverter" interface="org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter"/>
<extensionPoint name="expectedTypesContributor" interface="org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesContributor"/>
<extensionPoint name="positionManagerDelegate" interface="org.jetbrains.plugins.groovy.extensions.debugger.ScriptPositionManagerHelper"/>
<extensionPoint name="compilerExtension" interface="org.jetbrains.plugins.groovy.compiler.GroovyCompilerExtension"/>
@@ -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<GroovyExpectedTypesContributor> EP_NAME = ExtensionPointName.create("org.intellij.groovy.expectedTypesContributor");
public abstract List<TypeConstraint> calculateTypeConstraints(@NotNull GrExpression expression);
}
@@ -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<TypeConstraint> custom = new ArrayList<TypeConstraint>();
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<PsiType> getDefaultExpectedTypes(GrExpression element) {
final LinkedHashSet<PsiType> result = new LinkedHashSet<PsiType>();
for (TypeConstraint constraint : calculateTypeConstraints(element)) {
result.add(constraint.getDefaultType());
}
return result;
}
@@ -235,6 +235,20 @@ class Foo<T> {
@Typed Foo<String> bar() {
return [foo: { it.subs<caret> }]
}
"""
myFixture.completeBasic()
assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
}
public void testClosureInListInstantiation() throws Exception {
myFixture.configureByText "a.groovy", """
class Foo {
def Foo(int a, Function1<String, Integer> f) {}
}
@Typed Foo foo() {
[239, { s -> s.subs<caret> }]
}
"""
myFixture.completeBasic()
assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"