parameter info for closures

This commit is contained in:
Maxim Medvedev
2010-07-30 14:43:37 +04:00
parent f44d9b9c74
commit ef626ff007
10 changed files with 128 additions and 116 deletions
@@ -264,7 +264,7 @@ public class GroovyCompletionContributor extends CompletionContributor {
}
else if (call instanceof GrCallExpression) {
GrCallExpression constructorCall = (GrCallExpression)call;
ContainerUtil.addAll(results, constructorCall.getMethodVariants(null));
ContainerUtil.addAll(results, constructorCall.getCallVariants(null));
final PsiType type = ((GrCallExpression)call).getType();
if (type instanceof PsiClassType) {
final PsiClass psiClass = ((PsiClassType)type).resolve();
@@ -114,7 +114,7 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandler<GroovyPs
}
public void showParameterInfo(@NotNull GroovyPsiElement place, CreateParameterInfoContext context) {
GroovyResolveResult[] variants = ResolveUtil.getMethodVariants(place);
GroovyResolveResult[] variants = ResolveUtil.getCallVariants(place);
final List<GroovyResolveResult> namedElements = ContainerUtil.findAll(variants, new Condition<GroovyResolveResult>() {
public boolean value(GroovyResolveResult groovyResolveResult) {
final PsiElement element = groovyResolveResult.getElement();
@@ -43,7 +43,7 @@ public interface GrCallExpression extends GrExpression, GrCall {
PsiMethod resolveMethod();
@NotNull
GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument);
GroovyResolveResult[] getCallVariants(@Nullable GrExpression upToArgument);
//PsiElement addNamedArgument(GrNamedArgument argument);
}
@@ -127,7 +127,7 @@ public class GroovyExpectedTypesProvider {
final int closureIndex = closureArgs.indexOf(myExpression);
if (closureIndex >= 0) {
List<TypeConstraint> constraints = new ArrayList<TypeConstraint>();
for (GroovyResolveResult variant : ResolveUtil.getMethodVariants(myExpression)) {
for (GroovyResolveResult variant : ResolveUtil.getCallVariants(myExpression)) {
PsiParameter[] parameters = getCallParameters(variant);
if (parameters == null || parameters.length == 0) continue;
@@ -178,7 +178,7 @@ public class GroovyExpectedTypesProvider {
int idx = list.getExpressionArgumentIndex(myExpression);
List<TypeConstraint> constraints = new ArrayList<TypeConstraint>();
for (GroovyResolveResult variant : ResolveUtil.getMethodVariants(list)) {
for (GroovyResolveResult variant : ResolveUtil.getCallVariants(list)) {
PsiParameter[] parameters = getCallParameters(variant);
if (parameters == null || parameters.length <= idx) continue;
PsiType parameterType = variant.getSubstitutor().substitute(parameters[idx].getType());
@@ -182,7 +182,7 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx
}
@NotNull
public GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument) {
public GroovyResolveResult[] getCallVariants(@Nullable GrExpression upToArgument) {
final GrCodeReferenceElement referenceElement = getReferenceElement();
if (referenceElement == null) return GroovyResolveResult.EMPTY_ARRAY;
final GroovyResolveResult[] classResults = referenceElement.multiResolve(false);
@@ -77,6 +77,120 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
super(node);
}
public GroovyResolveResult[] resolveTypeOrProperty() {
String name = getReferenceName();
if (name == null) return GroovyResolveResult.EMPTY_ARRAY;
EnumSet<ClassHint.ResolveKind> kinds = getParent() instanceof GrReferenceExpression
? EnumSet.of(ClassHint.ResolveKind.CLASS, ClassHint.ResolveKind.PACKAGE)
: EnumSet.of(ClassHint.ResolveKind.CLASS);
boolean hasAt = hasAt();
GroovyResolveResult[] classCandidates = GroovyResolveResult.EMPTY_ARRAY;
if (!hasAt) {
ResolverProcessor classProcessor = new ClassResolverProcessor(getReferenceName(), this, kinds);
resolveImpl(classProcessor);
classCandidates = classProcessor.getCandidates();
for (GroovyResolveResult classCandidate : classCandidates) {
final PsiElement element = classCandidate.getElement();
if (element instanceof PsiClass && ((PsiClass)element).isEnum()) {
return classCandidates;
}
}
}
ResolverProcessor processor = new PropertyResolverProcessor(name, this);
resolveImpl(processor);
final GroovyResolveResult[] fieldCandidates = processor.getCandidates();
if (hasAt) {
return fieldCandidates;
}
//if reference expression is in class we need to return field instead of accessor method
for (GroovyResolveResult candidate : fieldCandidates) {
final PsiElement element = candidate.getElement();
if (element instanceof PsiField) {
final PsiClass containingClass = ((PsiField)element).getContainingClass();
if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, this, true)) return fieldCandidates;
} else {
return fieldCandidates;
}
}
final boolean isLValue = PsiUtil.isLValue(this);
String[] names;
names = isLValue ? GroovyPropertyUtils.suggestSettersName(name) : GroovyPropertyUtils.suggestGettersName(name);
List<GroovyResolveResult> accessorResults = new ArrayList<GroovyResolveResult>();
for (String getterName : names) {
AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(getterName, this, !isLValue);
resolveImpl(accessorResolver);
final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); //can be only one candidate
if (candidates.length == 1 && candidates[0].isStaticsOK()) {
return candidates;
}
else {
ContainerUtil.addAll(accessorResults, candidates);
}
}
if (fieldCandidates.length > 0) return fieldCandidates;
if (accessorResults.size() > 0) return new GroovyResolveResult[]{accessorResults.get(0)};
return classCandidates;
}
public GroovyResolveResult[] resolveMethodOrProperty() {
return resolveMethodOrProperty(false, null);
}
public GroovyResolveResult[] getCallVariants(GrExpression upToArgument) {
return resolveMethodOrProperty(true, upToArgument);
}
private GroovyResolveResult[] resolveMethodOrProperty(boolean allVariants, GrExpression upToArgument) {
String name = getReferenceName();
if (name == null) return GroovyResolveResult.EMPTY_ARRAY;
final PsiType[] argTypes = PsiUtil.getArgumentTypes(this, false, upToArgument);
MethodResolverProcessor methodResolver = runMethodResolverProcessor(argTypes, allVariants);
assert methodResolver != null;
if (!allVariants && methodResolver.hasApplicableCandidates()) return methodResolver.getCandidates();
final String[] names = GroovyPropertyUtils.suggestGettersName(name);
List<GroovyResolveResult> list = new ArrayList<GroovyResolveResult>();
for (String getterName : names) {
AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, this, true);
resolveImpl(getterResolver);
final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate
if (!allVariants && candidates.length == 1 && candidates[0].isStaticsOK()) {
putUserData(IS_RESOLVED_TO_GETTER, true);
return candidates;
}
else {
ContainerUtil.addAll(list, candidates);
}
}
PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, this);
resolveImpl(propertyResolver);
if (!allVariants && propertyResolver.hasCandidates()) return propertyResolver.getCandidates();
if (allVariants) {
if (list.isEmpty()) ContainerUtil.addAll(list, propertyResolver.getCandidates());
ContainerUtil.addAll(list, methodResolver.getCandidates());
return list.toArray(new GroovyResolveResult[list.size()]);
}
if (methodResolver.hasCandidates()) {
return methodResolver.getCandidates();
}
else if (list.size() > 0) {
putUserData(IS_RESOLVED_TO_GETTER, true);
return list.toArray(new GroovyResolveResult[list.size()]);
}
return GroovyResolveResult.EMPTY_ARRAY;
}
public void accept(GroovyElementVisitor visitor) {
visitor.visitReferenceExpression(this);
}
@@ -422,108 +536,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
switch (kind) {
case METHOD_OR_PROPERTY:
return resolveMethodOrProperty(refExpr, name);
return refExpr.resolveMethodOrProperty();
case TYPE_OR_PROPERTY:
return resolveTypeOrProperty(refExpr, name);
return refExpr.resolveTypeOrProperty();
default:
return GroovyResolveResult.EMPTY_ARRAY;
}
}
private static GroovyResolveResult[] resolveTypeOrProperty(GrReferenceExpressionImpl refExpr, String name) {
EnumSet<ClassHint.ResolveKind> kinds = refExpr.getParent() instanceof GrReferenceExpression
? EnumSet.of(ClassHint.ResolveKind.CLASS, ClassHint.ResolveKind.PACKAGE)
: EnumSet.of(ClassHint.ResolveKind.CLASS);
boolean hasAt = refExpr.hasAt();
GroovyResolveResult[] classCandidates = GroovyResolveResult.EMPTY_ARRAY;
if (!hasAt) {
ResolverProcessor classProcessor = new ClassResolverProcessor(refExpr.getReferenceName(), refExpr, kinds);
refExpr.resolveImpl(classProcessor);
classCandidates = classProcessor.getCandidates();
for (GroovyResolveResult classCandidate : classCandidates) {
final PsiElement element = classCandidate.getElement();
if (element instanceof PsiClass && ((PsiClass)element).isEnum()) {
return classCandidates;
}
}
}
ResolverProcessor processor = new PropertyResolverProcessor(name, refExpr);
refExpr.resolveImpl(processor);
final GroovyResolveResult[] fieldCandidates = processor.getCandidates();
if (refExpr.hasAt()) {
return fieldCandidates;
}
//if reference expression is in class we need to return field instead of accessor method
for (GroovyResolveResult candidate : fieldCandidates) {
final PsiElement element = candidate.getElement();
if (element instanceof PsiField) {
final PsiClass containingClass = ((PsiField)element).getContainingClass();
if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, refExpr, true)) return fieldCandidates;
} else {
return fieldCandidates;
}
}
final boolean isLValue = PsiUtil.isLValue(refExpr);
String[] names;
names = isLValue ? GroovyPropertyUtils.suggestSettersName(name) : GroovyPropertyUtils.suggestGettersName(name);
List<GroovyResolveResult> accessorResults = new ArrayList<GroovyResolveResult>();
for (String getterName : names) {
AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(getterName, refExpr, !isLValue);
refExpr.resolveImpl(accessorResolver);
final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); //can be only one candidate
if (candidates.length == 1 && candidates[0].isStaticsOK()) {
return candidates;
}
else {
ContainerUtil.addAll(accessorResults, candidates);
}
}
if (fieldCandidates.length > 0) return fieldCandidates;
if (accessorResults.size() > 0) return new GroovyResolveResult[]{accessorResults.get(0)};
return classCandidates;
}
private static GroovyResolveResult[] resolveMethodOrProperty(GrReferenceExpressionImpl refExpr, String name) {
final PsiType[] argTypes = PsiUtil.getArgumentTypes(refExpr, false);
MethodResolverProcessor methodResolver = refExpr.runMethodResolverProcessor(argTypes, false);
assert methodResolver != null;
if (methodResolver.hasApplicableCandidates()) return methodResolver.getCandidates();
final String[] names = GroovyPropertyUtils.suggestGettersName(name);
List<GroovyResolveResult> list = new ArrayList<GroovyResolveResult>();
for (String getterName : names) {
AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, refExpr, true);
refExpr.resolveImpl(getterResolver);
final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate
if (candidates.length == 1 && candidates[0].isStaticsOK()) {
refExpr.putUserData(IS_RESOLVED_TO_GETTER, true);
return candidates;
}
else {
ContainerUtil.addAll(list, candidates);
}
}
PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, refExpr);
refExpr.resolveImpl(propertyResolver);
if (propertyResolver.hasCandidates()) return propertyResolver.getCandidates();
if (methodResolver.hasCandidates()) {
return methodResolver.getCandidates();
}
else if (list.size() > 0) {
refExpr.putUserData(IS_RESOLVED_TO_GETTER, true);
return list.toArray(new GroovyResolveResult[list.size()]);
}
return GroovyResolveResult.EMPTY_ARRAY;
}
}
private void resolveImpl(ResolverProcessor processor) {
@@ -41,7 +41,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrRefer
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
import java.util.ArrayList;
@@ -187,17 +186,11 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
}
@NotNull
public GroovyResolveResult[] getMethodVariants(@Nullable GrExpression upToArgument) {
public GroovyResolveResult[] getCallVariants(@Nullable GrExpression upToArgument) {
final GrExpression invoked = getInvokedExpression();
if (!(invoked instanceof GrReferenceExpressionImpl)) return GroovyResolveResult.EMPTY_ARRAY;
final PsiType[] partialArgs = PsiUtil.getArgumentTypes(invoked, false, upToArgument);
final MethodResolverProcessor processor = ((GrReferenceExpressionImpl)invoked).runMethodResolverProcessor(partialArgs, true);
if (processor != null) {
return processor.getCandidates();
}
return GroovyResolveResult.EMPTY_ARRAY;
return ((GrReferenceExpressionImpl)invoked).getCallVariants(upToArgument);
}
}
@@ -42,7 +42,7 @@ public class GroovyExpressionPattern<T extends GrExpression, Self extends Groovy
public GroovyMethodCallPattern methodCall(final ElementPattern<? extends PsiMethod> method) {
return new GroovyMethodCallPattern().and(this).with(new PatternCondition<GrCallExpression>("methodCall") {
public boolean accepts(@NotNull GrCallExpression callExpression, ProcessingContext context) {
final GroovyResolveResult[] results = callExpression.getMethodVariants(null);
final GroovyResolveResult[] results = callExpression.getCallVariants(null);
for (GroovyResolveResult result : results) {
if (method.getCondition().accepts(result.getElement(), context)) {
return true;
@@ -632,7 +632,7 @@ public class PsiUtil {
}
public static boolean isRawMethodCall(GrMethodCallExpression call) {
final GroovyResolveResult[] resolveResults = call.getMethodVariants(null);
final GroovyResolveResult[] resolveResults = call.getCallVariants(null);
if (resolveResults.length == 0) return false;
final PsiElement element = resolveResults[0].getElement();
if (element instanceof PsiMethod) {
@@ -439,11 +439,11 @@ public class ResolveUtil {
return true;
}
public static GroovyResolveResult[] getMethodVariants(GroovyPsiElement place) {
public static GroovyResolveResult[] getCallVariants(GroovyPsiElement place) {
final PsiElement parent = place.getParent();
GroovyResolveResult[] variants = GroovyResolveResult.EMPTY_ARRAY;
if (parent instanceof GrCallExpression) {
variants = ((GrCallExpression) parent).getMethodVariants(place instanceof GrExpression ? (GrExpression)place : null);
variants = ((GrCallExpression) parent).getCallVariants(place instanceof GrExpression ? (GrExpression)place : null);
} else if (parent instanceof GrConstructorInvocation) {
final PsiClass clazz = ((GrConstructorInvocation) parent).getDelegatedClass();
if (clazz != null) {