generics in closure completion

This commit is contained in:
Max Medvedev
2012-09-28 18:23:24 +03:00
parent a6816dd0ef
commit 0f0aa6f534
5 changed files with 44 additions and 29 deletions
@@ -1,20 +1,20 @@
contributor(ctype: 'org.codehaus.groovy.runtime.DefaultGroovyMethods') {
closureInMethod(method: [name: 'eachWithIndex', params: ['T', 'groovy.lang.Closure']], params: [entry: null, i: 'int'])
closureInMethod(method: [name: 'inject', params: ['java.lang.Object', 'groovy.lang.Closure']], params: [acc: null, val: null])
//closureInMethod(method: [name: 'eachWithIndex', params: ['T', 'groovy.lang.Closure']], params: [entry: null, i: 'int'])
closureInMethod(method: [name: 'inject', params: ['java.util.Collection<T>', 'groovy.lang.Closure']], params: [acc: null, val: 'T'])
closureInMethod(method: [name: 'min', params: ['java.util.Collection', 'groovy.lang.Closure']], params: [a: null, b: null])
closureInMethod(method: [name: 'min', params: ['java.util.Iterator', 'groovy.lang.Closure']], params: [a: null, b: null])
closureInMethod(method: [name: 'min', params: ['java.util.Map', 'groovy.lang.Closure']], params: [a: null, b: null])
closureInMethod(method: [name: 'min', params: ['java.util.Collection<T>', 'groovy.lang.Closure']], params: [a: 'T', b: "T"])
closureInMethod(method: [name: 'min', params: ['java.util.Iterator<T>', 'groovy.lang.Closure']], params: [a: 'T', b: 'T'])
closureInMethod(method: [name: 'min', params: ['java.util.Map<K, V>', 'groovy.lang.Closure']], params: [a: 'java.util.Map.Entry<K, V>', b: 'java.util.Map.Entry<K, V>'])
closureInMethod(method: [name: 'min', params: ['java.util.Collection', 'groovy.lang.Closure']], params: [a: null])
closureInMethod(method: [name: 'min', params: ['java.util.Iterator', 'groovy.lang.Closure']], params: [a: null])
closureInMethod(method: [name: 'min', params: ['java.util.Map', 'groovy.lang.Closure']], params: [a: null])
closureInMethod(method: [name: 'min', params: ['java.util.Collection<T>', 'groovy.lang.Closure']], params: [a: 'T'])
closureInMethod(method: [name: 'min', params: ['java.util.Iterator<T>', 'groovy.lang.Closure']], params: [a: 'T'])
closureInMethod(method: [name: 'min', params: ['java.util.Map<K, V>', 'groovy.lang.Closure']], params: [a: 'java.util.Map.Entry<K, V>'])
closureInMethod(method: [name: 'max', params: ['java.util.Collection', 'groovy.lang.Closure']], params: [a: null, b: null])
closureInMethod(method: [name: 'max', params: ['java.util.Iterator', 'groovy.lang.Closure']], params: [a: null, b: null])
closureInMethod(method: [name: 'max', params: ['java.util.Map', 'groovy.lang.Closure']], params: [a: null, b: null])
closureInMethod(method: [name: 'max', params: ['java.util.Collection<T>', 'groovy.lang.Closure']], params: [a: 'T', b: 'T'])
closureInMethod(method: [name: 'max', params: ['java.util.Iterator<T>', 'groovy.lang.Closure']], params: [a: 'T', b: 'T'])
closureInMethod(method: [name: 'max', params: ['java.util.Map<K, V>', 'groovy.lang.Closure']], params: [a: 'java.util.Map.Entry<K, V>', b: 'java.util.Map.Entry<K, V>'])
closureInMethod(method: [name: 'max', params: ['java.util.Collection', 'groovy.lang.Closure']], params: [a: null])
closureInMethod(method: [name: 'max', params: ['java.util.Iterator', 'groovy.lang.Closure']], params: [a: null])
closureInMethod(method: [name: 'max', params: ['java.util.Map', 'groovy.lang.Closure']], params: [a: null])
closureInMethod(method: [name: 'max', params: ['java.util.Collection<T>', 'groovy.lang.Closure']], params: [a: 'T'])
closureInMethod(method: [name: 'max', params: ['java.util.Iterator<T>', 'groovy.lang.Closure']], params: [a: 'T'])
closureInMethod(method: [name: 'max', params: ['java.util.Map<K, V>', 'groovy.lang.Closure']], params: [a: 'java.util.Map.Entry<K, V>'])
}
@@ -25,8 +25,10 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.compiled.ClsMethodImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
@@ -52,12 +54,16 @@ public class ClosureTemplateBuilder {
StringBuilder buffer = new StringBuilder();
buffer.append("{");
List<PsiType> paramTypes = ContainerUtil.newArrayList();
for (ClosureParameterInfo parameter : parameters) {
final String type = parameter.getType();
final String name = parameter.getName();
if (type != null) {
if (method instanceof ClsMethodImpl) method = ((ClsMethodImpl)method).getSourceMirrorMethod();
final PsiType fromText = JavaPsiFacade.getElementFactory(project).createTypeFromText(type, method);
final PsiType substituted = TypeConversionUtil.erasure(substitutor.substitute(fromText));
paramTypes.add(substituted);
buffer.append(substituted.getCanonicalText()).append(" ");
}
else {
@@ -78,12 +84,13 @@ public class ClosureTemplateBuilder {
final TemplateBuilderImpl builder = new TemplateBuilderImpl(templateClosure);
int i = 0;
for (GrParameter p : templateClosure.getParameters()) {
final GrTypeElement typeElement = p.getTypeElementGroovy();
final PsiElement nameIdentifier = p.getNameIdentifierGroovy();
if (typeElement != null) {
final TypeConstraint[] typeConstraints = {SupertypeConstraint.create(typeElement.getType())};
final TypeConstraint[] typeConstraints = {SupertypeConstraint.create(paramTypes.get(i++))};
final ChooseTypeExpression expression = new ChooseTypeExpression(typeConstraints, PsiManager.getInstance(project), nameIdentifier.getResolveScope());
builder.replaceElement(typeElement, expression);
}
@@ -58,6 +58,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.SubstitutorComputer;
import java.util.*;
@@ -288,7 +289,7 @@ public class CompleteReferenceExpression {
private static void addVariantsWithSameQualifier(PrefixMatcher matcher, PsiElement element,
GrReferenceExpression patternExpression,
GrExpression patternQualifier,
@Nullable GrExpression patternQualifier,
Set<String> result) {
if (element instanceof GrReferenceExpression && element != patternExpression && !PsiUtil.isLValue((GroovyPsiElement)element)) {
final GrReferenceExpression refExpr = (GrReferenceExpression)element;
@@ -377,6 +378,7 @@ public class CompleteReferenceExpression {
private final boolean myMethodPointerOperator;
private final boolean myIsMap;
private Set<String> myNonDeclaredVars = new com.intellij.util.containers.HashSet<String>();
private final SubstitutorComputer mySubstitutorComputer;
protected CompleteReferenceProcessor(GrReferenceExpression place, Consumer<LookupElement> consumer, @NotNull PrefixMatcher matcher, CompletionParameters parameters) {
super(null, EnumSet.allOf(ResolveKind.class), place, PsiType.EMPTY_ARRAY);
@@ -391,6 +393,8 @@ public class CompleteReferenceExpression {
myFieldPointerOperator = place.hasAt();
myMethodPointerOperator = place.getDotTokenType() == GroovyTokenTypes.mMEMBER_POINTER;
myIsMap = isMap(place);
final PsiType thisType = GrReferenceResolveUtil.getThisType(place);
mySubstitutorComputer = new SubstitutorComputer(thisType, PsiType.EMPTY_ARRAY, PsiType.EMPTY_ARRAY, true, place, place.getParent());
}
private static boolean shouldSkipPackages(GrReferenceExpression place) {
@@ -416,6 +420,9 @@ public class CompleteReferenceExpression {
PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
if (element instanceof PsiMethod) {
substitutor = mySubstitutorComputer.obtainSubstitutor(substitutor, (PsiMethod)element, state);
}
consume(new GroovyResolveResultImpl(namedElement, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
}
@@ -189,7 +189,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
List<GroovyResolveResult> accessorResults = new ArrayList<GroovyResolveResult>();
for (String accessorName : accessorNames) {
AccessorResolverProcessor accessorResolver =
new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments());
new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, GrReferenceResolveUtil.getThisType(this), getTypeArguments());
GrReferenceResolveUtil.resolveImpl(accessorResolver, this);
final GroovyResolveResult[] candidates = accessorResolver.getCandidates();
@@ -300,7 +300,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
//search for getters
for (String getterName : GroovyPropertyUtils.suggestGettersName(name)) {
AccessorResolverProcessor getterResolver =
new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, getThisType(), getTypeArguments());
new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, GrReferenceResolveUtil.getThisType(this), getTypeArguments());
GrReferenceResolveUtil.resolveImpl(getterResolver, this);
final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate
if (!allVariants && candidates.length == 1) {
@@ -358,7 +358,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
argTypes[i] = TypeConversionUtil.erasure(argTypes[i]);
}
}
return new MethodResolverProcessor(name, this, false, getThisType(), argTypes, getTypeArguments(), allVariants, byShape);
return new MethodResolverProcessor(name, this, false, GrReferenceResolveUtil.getThisType(this), argTypes, getTypeArguments(), allVariants, byShape);
}
public void accept(GroovyElementVisitor visitor) {
@@ -676,16 +676,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
}
private PsiType getThisType() {
GrExpression qualifier = getQualifierExpression();
if (qualifier != null) {
PsiType qType = qualifier.getType();
if (qType != null) return qType;
}
return TypesUtil.getJavaLangObject(this);
}
enum Kind {
TYPE_OR_PROPERTY,
METHOD_OR_PROPERTY,
@@ -255,4 +255,15 @@ public class GrReferenceResolveUtil {
}
return null;
}
public static PsiType getThisType(GrReferenceExpression ref) {
GrExpression qualifier = ref.getQualifierExpression();
if (qualifier != null) {
PsiType qType = qualifier.getType();
if (qType != null) return qType;
}
return TypesUtil.getJavaLangObject(ref);
}
}