import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
-import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
PsiType[] argumentTypes = PsiUtil.getArgumentTypes(place, false, true);
if (argumentTypes == null) return;
- final PsiType[] paramTypes = PsiUtil.skipOptionalClosureParameters(argumentTypes.length, (GrClosureType)type);
- if (!areTypesCompatibleForCallingClosure(argumentTypes, paramTypes, place.getManager(), place.getResolveScope())) {
+ if (!PsiUtil.isApplicable(argumentTypes, (GrClosureType)type, element.getManager())) {
final String typesString = buildArgTypesList(argumentTypes);
String message = GroovyBundle.message("cannot.apply.method.or.closure", variable.getName(), typesString);
PsiElement elementToHighlight = PsiUtil.getArgumentsElement(place);
}
}
- private static boolean areTypesCompatibleForCallingClosure(PsiType[] argumentTypes,
- PsiType[] paramTypes,
- PsiManager manager,
- GlobalSearchScope resolveScope) {
- if (argumentTypes.length != paramTypes.length) return false;
- for (int i = 0; i < argumentTypes.length; i++) {
- final PsiType paramType = TypesUtil.boxPrimitiveType(paramTypes[i], manager, resolveScope);
- final PsiType argType = argumentTypes[i];
- if (!TypesUtil.isAssignableByMethodCallConversion(paramType, argType, manager, resolveScope)) return false;
- }
- return true;
- }
-
private static void registerAddImportFixes(GrReferenceElement refElement, Annotation annotation) {
final String referenceName = refElement.getReferenceName();
//noinspection ConstantConditions
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
if (expr.getTextRange().contains(offset)) return idx;
idx++;
}
- }
+ }
return -1;
}
} else if (element instanceof PsiClass) {
buffer.append("no parameters");
- } else if (element instanceof GrVariable) {
- final PsiType type = ((GrVariable) element).getTypeGroovy();
+ }
+ else if (element instanceof GrVariable) {
+ final PsiType type = ((GrVariable)element).getTypeGroovy();
if (type instanceof GrClosureType) {
- PsiType[] parameterTypes = ((GrClosureType) type).getClosureParameterTypes();
- if (parameterTypes.length > 0) {
- for (int i = 0; i < parameterTypes.length; i++) {
+ GrClosureParameter[] parameters = ((GrClosureType)type).getSignature().getParameters();
+ if (parameters.length > 0) {
+ for (int i = 0; i < parameters.length; i++) {
if (i > 0) buffer.append(", ");
- PsiType parameterType = ((GrClosureType) type).getClosureParameterTypes()[i];
- buffer.append(parameterType.getPresentableText());
+ final String name = parameters[i].getName();
+ final PsiType psiType = parameters[i].getType();
+ if (name == null) {
+ buffer.append(psiType == null ? "null" : psiType.getPresentableText());
+ }
+ else {
+ String typeText = psiType == null ? "def" : psiType.getPresentableText();
+ buffer.append(typeText).append(' ').append(name);
+ final GrExpression initializer = parameters[i].getDefaultInitializer();
+ if (initializer != null) {
+ buffer.append(" = ").append(initializer.getText());
+ }
+ }
}
- } else {
+ }
+ else {
buffer.append("no parameters");
}
}
--- /dev/null
+/*
+ * Copyright 2000-2009 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.psi.api.types;
+
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiType;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public interface GrClosureParameter {
+ PsiParameter[] EMPTY_ARRAY = new PsiParameter[0];
+
+ @Nullable
+ PsiType getType();
+
+ boolean isOptional();
+
+ @Nullable
+ GrExpression getDefaultInitializer();
+
+ boolean isValid();
+
+ @Nullable
+ String getName();
+}
--- /dev/null
+/*
+ * Copyright 2000-2009 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.psi.api.types;
+
+import com.intellij.psi.PsiType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public interface GrClosureSignature {
+ @NotNull
+ GrClosureParameter[] getParameters();
+
+ boolean isVarargs();
+
+ @Nullable
+ PsiType getReturnType();
+
+ @Nullable
+ GrClosureSignature curry(int count);
+
+ boolean isValid();
+}
--- /dev/null
+/*
+ * 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.psi.impl;
+
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
+import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
+import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureImpl;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class GrClosureSignatureUtil {
+ private GrClosureSignatureUtil() {
+ }
+
+ public static GrClosureSignature createSignature(PsiMethod method) {
+ return new GrClosureSignatureImpl(method);
+ }
+
+ public static GrClosureSignature createSignature(GrClosableBlock block) {
+ return new GrClosureSignatureImpl(block);
+ }
+
+ public static GrClosureSignature createSignature(PsiMethod method, PsiSubstitutor substitutor) {
+ return new GrClosureSignatureImpl(method, substitutor);
+ }
+
+ public static GrClosureSignature createSignature(PsiParameter[] parameters, PsiType returnType) {
+ return new GrClosureSignatureImpl(parameters, returnType);
+ }
+
+ public static boolean isSignatureApplicable(GrClosureSignature signature, PsiType[] args, PsiManager manager, GlobalSearchScope scope) {
+ GrClosureParameter[] params = signature.getParameters();
+ if (args.length > params.length && !signature.isVarargs()) return false;
+ int optional = getOptionalParamCount(signature);
+ int notOptional = params.length - optional;
+ if (signature.isVarargs()) notOptional--;
+ if (notOptional > args.length) return false;
+
+ if (signature.isVarargs()) {
+ if (isApplicable(params, args, params.length - 1, args.length, manager, scope)) return true;
+
+ PsiType lastType = params[params.length - 1].getType();
+ assert lastType instanceof PsiArrayType;
+ PsiType varargType = ((PsiArrayType)lastType).getComponentType();
+
+ for (int argCount = args.length - 1; argCount >= notOptional; argCount--) {
+ if (!isApplicable(params, args, params.length - 1, argCount, manager, scope)) continue;
+ if (!TypesUtil.isAssignableByMethodCallConversion(varargType, args[argCount], manager, scope)) continue;
+ return true;
+ }
+ return false;
+ }
+ else {
+ return isApplicable(params, args, params.length, args.length, manager, scope);
+ }
+ }
+
+ private static boolean isApplicable(GrClosureParameter[] params,
+ PsiType[] args,
+ int paramCount,
+ int argCount,
+ PsiManager manager,
+ GlobalSearchScope scope) {
+ int optional = getOptionalParamCount(params);
+ int notOptional = paramCount - optional;
+ int optionalArgs = argCount - notOptional;
+ int cur = 0;
+ for (int i = 0; i < argCount; i++, cur++) {
+ while (optionalArgs == 0 && cur < paramCount && params[cur].isOptional()) {
+ cur++;
+ }
+ if (cur == paramCount) return false;
+ if (params[cur].isOptional()) optionalArgs--;
+ if (!TypesUtil.isAssignableByMethodCallConversion(params[cur].getType(), args[i], manager, scope)) return false;
+ }
+ return true;
+ }
+
+
+ public static int getOptionalParamCount(GrClosureSignature signature) {
+ return getOptionalParamCount(signature.getParameters());
+ }
+
+ public static int getOptionalParamCount(GrClosureParameter[] parameters) {
+
+ int count = 0;
+ for (GrClosureParameter parameter : parameters) {
+ if (parameter.isOptional()) count++;
+ }
+ return count;
+ }
+}
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
/**
* @author ven
*/
public class GrClosureType extends PsiClassType {
private final GlobalSearchScope myScope;
- @Nullable
- private final PsiType myReturnType;
- private final PsiType[] myParameterTypes;
- private final boolean[] myOptionals;
private final PsiManager myManager;
+ private final GrClosureSignature mySignature;
- private GrClosureType(GlobalSearchScope scope,
- @Nullable PsiType returnType,
- PsiType[] parameters,
- boolean[] optionals,
- PsiManager manager, LanguageLevel languageLevel) {
+ private GrClosureType(LanguageLevel languageLevel, GlobalSearchScope scope, PsiManager manager, GrClosureSignature closureSignature) {
super(languageLevel);
myScope = scope;
- myReturnType = returnType;
- myParameterTypes = parameters;
- myOptionals = optionals;
myManager = manager;
+ mySignature = closureSignature;
}
@Nullable
return JavaPsiFacade.getInstance(myManager.getProject()).findClass(GrClosableBlock.GROOVY_LANG_CLOSURE, getResolveScope());
}
- @Nullable
- public PsiType getClosureReturnType() {
- return myReturnType;
- }
-
- public PsiType[] getClosureParameterTypes() {
- return myParameterTypes;
- }
-
- public boolean isOptionalParameter(int parameterIndex) {
- return myOptionals[parameterIndex];
- }
-
public String getClassName() {
return "Closure";
}
return true;
}
+ @Nullable
public PsiElement getCurrentFileResolveScope() {
return null;
}
return resolved.getQualifiedName();
}
+ @Nullable
public String getInternalCanonicalText() {
return getCanonicalText();
}
public boolean isValid() {
- if (myParameterTypes.length > 0 && !myParameterTypes[0].isValid()) return false;
- return myReturnType == null || myReturnType.isValid();
+ return mySignature.isValid();
}
public boolean equals(Object obj) {
if (obj instanceof GrClosureType) {
- GrClosureType other = (GrClosureType)obj;
- if (!Comparing.equal(myReturnType, other.myReturnType)) return false;
- if (myParameterTypes.length != other.myParameterTypes.length) return false;
- for (int i = 0; i < myParameterTypes.length; i++) {
- if (myOptionals[i] != other.myOptionals[i]) return false;
- if (!other.myParameterTypes[i].equals(myParameterTypes[i])) return false;
- }
- return true;
+ return Comparing.equal(mySignature, ((GrClosureType)obj).mySignature);
}
return super.equals(obj);
public boolean isAssignableFrom(@NotNull PsiType type) {
if (type instanceof GrClosureType) {
GrClosureType other = (GrClosureType)type;
- if (myReturnType == null || other.myReturnType == null) {
- return myReturnType == null && other.myReturnType == null;
+ GrClosureSignature otherSignature = other.mySignature;
+
+ final PsiType myReturnType = mySignature.getReturnType();
+ final PsiType otherReturnType = otherSignature.getReturnType();
+ if (myReturnType == null || otherReturnType == null) {
+ return myReturnType == null && otherReturnType == null;
}
- if (!myReturnType.isAssignableFrom(other.myReturnType)) return false;
- if (myParameterTypes.length != other.myParameterTypes.length) return false;
- for (int i = 0; i < myParameterTypes.length; i++) {
- if (myOptionals[i] != other.myOptionals[i]) return false;
- if (!other.myParameterTypes[i].isAssignableFrom(myParameterTypes[i])) return false;
+
+ if (!myReturnType.isAssignableFrom(otherReturnType)) return false;
+
+ final GrClosureParameter[] myParameters = mySignature.getParameters();
+ final GrClosureParameter[] otherParameters = otherSignature.getParameters();
+
+ if (myParameters.length != otherParameters.length) return false;
+ for (int i = 0; i < myParameters.length; i++) {
+ if (myParameters[i].isOptional() != otherParameters[i].isOptional()) return false;
+ final PsiType otherParamType = otherParameters[i].getType();
+ final PsiType myParamType = myParameters[i].getType();
+ if (myParamType == null || otherParamType == null) {
+ if (myParamType != null || otherParamType != null) return false;
+ }
+ else if (!otherParamType.isAssignableFrom(myParamType)) return false;
}
return true;
}
}
public PsiClassType setLanguageLevel(final LanguageLevel languageLevel) {
- return create(myReturnType, myParameterTypes, myOptionals, myManager, myScope, languageLevel);
+ return create(mySignature, myManager, myScope, languageLevel);
}
public static GrClosureType create(GrClosableBlock closure) {
- return create(closure.getResolveScope(), closure.getReturnType(), closure.getAllParameters(), closure.getManager());
- }
-
- public static GrClosureType create(GlobalSearchScope scope, PsiType returnType, PsiParameter[] parameters, PsiManager manager) {
- PsiType[] parameterTypes = new PsiType[parameters.length];
- boolean[] optionals = new boolean[parameters.length];
- for (int i = 0; i < optionals.length; i++) {
- PsiParameter parameter = parameters[i];
- if (parameter instanceof GrParameter) {
- optionals[i] = ((GrParameter)parameter).isOptional();
- } else if (i == 0) { // for implicit "it" parameter
- optionals[i] = true;
- } else {
- optionals[i] = false;
- }
- parameterTypes[i] = parameter.getType();
- }
- return create(returnType, parameterTypes, optionals, manager, scope, LanguageLevel.JDK_1_5);
+ return create(GrClosureSignatureUtil.createSignature(closure), closure.getManager(), closure.getResolveScope(), LanguageLevel.JDK_1_5);
+ }
+
+ public static GrClosureType create(PsiMethod method, PsiSubstitutor substitutor) {
+ return create(GrClosureSignatureUtil.createSignature(method, substitutor), method.getManager(), GlobalSearchScope.allScope(method.getProject()), LanguageLevel.JDK_1_5);
+ }
+
+ public static GrClosureType create(PsiParameter[] parameters,
+ PsiType returnType,
+ PsiManager manager,
+ GlobalSearchScope scope,
+ LanguageLevel languageLevel) {
+ return create(GrClosureSignatureUtil.createSignature(parameters, returnType), manager, scope, languageLevel);
}
- public static GrClosureType create(PsiType returnType,
- PsiType[] parameterTypes,
- boolean[] optionals,
+ public static GrClosureType create(GrClosureSignature signature,
PsiManager manager,
- GlobalSearchScope scope, LanguageLevel languageLevel) {
- return new GrClosureType(scope, returnType, parameterTypes, optionals, manager,languageLevel);
+ GlobalSearchScope scope,
+ LanguageLevel languageLevel) {
+ return new GrClosureType(languageLevel, scope, manager, signature);
}
@Nullable
- public PsiType curry(int num) {
- if (num > myParameterTypes.length) return null;
- PsiType[] newParameterTypes = new PsiType[myParameterTypes.length - num];
- boolean[] newOptionals = new boolean[myParameterTypes.length - num];
- System.arraycopy(myParameterTypes, num, newParameterTypes, 0, newParameterTypes.length);
- System.arraycopy(myOptionals, num, newOptionals, 0, newOptionals.length);
- return create(myReturnType, newParameterTypes, newOptionals, myManager, myScope, myLanguageLevel);
+ public PsiType curry(int count) {
+ final GrClosureSignature newSignature = mySignature.curry(count);
+ if (newSignature == null) return null;
+ return create(newSignature, myManager, myScope, myLanguageLevel);
+ }
+
+ public GrClosureSignature getSignature() {
+ return mySignature;
+ }
+
+ public PsiType[] getClosureParameterTypes() {
+ final GrClosureParameter[] parameters = mySignature.getParameters();
+ final PsiType[] types = new PsiType[parameters.length];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = parameters[i].getType();
+ }
+ return types;
}
}
PsiElement resolved = resolveResult.getElement();
if (dotType == GroovyTokenTypes.mMEMBER_POINTER) {
if (resolved instanceof PsiMethod) {
- PsiMethod method = (PsiMethod) resolved;
- PsiType returnType = resolveResult.getSubstitutor().substitute(method.getReturnType());
- return GrClosureType.create(getResolveScope(), returnType, method.getParameterList().getParameters(), getManager());
+ return GrClosureType.create((PsiMethod) resolved, resolveResult.getSubstitutor());
}
return JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeByFQClassName(GrClosableBlock.GROOVY_LANG_CLOSURE, getResolveScope());
}
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.TypeConversionUtil;
+import com.intellij.util.containers.ComparatorUtil;
import com.intellij.util.containers.HashMap;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
+import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureImpl;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
else if (type1 instanceof GrClosureType && type2 instanceof GrClosureType) {
GrClosureType clType1 = (GrClosureType)type1;
GrClosureType clType2 = (GrClosureType)type2;
- PsiType[] parameterTypes1 = clType1.getClosureParameterTypes();
- PsiType[] parameterTypes2 = clType2.getClosureParameterTypes();
- if (parameterTypes1.length == parameterTypes2.length) {
- PsiType[] paramTypes = new PsiType[parameterTypes1.length];
- boolean[] opts = new boolean[parameterTypes1.length];
- for (int i = 0; i < paramTypes.length; i++) {
- paramTypes[i] = GenericsUtil.getGreatestLowerBound(parameterTypes1[i], parameterTypes2[i]);
- opts[i] = clType1.isOptionalParameter(i) && clType2.isOptionalParameter(i);
- }
- final PsiType ret1 = clType1.getClosureReturnType();
- final PsiType ret2 = clType2.getClosureReturnType();
- PsiType returnType = ret1 == null ? ret2 : ret2 == null ? ret1 : getLeastUpperBound(ret1, ret2, manager);
+ GrClosureSignature signature1=clType1.getSignature();
+ GrClosureSignature signature2=clType2.getSignature();
+
+ GrClosureParameter[] parameters1 = signature1.getParameters();
+ GrClosureParameter[] parameters2 = signature2.getParameters();
+
+ if (parameters1.length == parameters2.length) {
+ final GrClosureSignature signature = GrClosureSignatureImpl.getLeastUpperBound(signature1, signature2, manager);
GlobalSearchScope scope = clType1.getResolveScope().intersectWith(clType2.getResolveScope());
- return GrClosureType.create(returnType, paramTypes, opts, manager, scope, LanguageLevel.JDK_1_5);
+ final LanguageLevel languageLevel = ComparatorUtil.max(clType1.getLanguageLevel(), clType2.getLanguageLevel());
+ return GrClosureType.create(signature, manager, scope, languageLevel);
}
}
else if (GrStringUtil.GROOVY_LANG_GSTRING.equals(type1.getCanonicalText()) &&
*/
public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements GrMethodCallExpression {
private static final Function<GrMethodCallExpressionImpl, PsiType> TYPES_CALCULATOR = new Function<GrMethodCallExpressionImpl, PsiType>() {
+ @Nullable
public PsiType fun(GrMethodCallExpressionImpl callExpression) {
GrExpression invoked = callExpression.getInvokedExpression();
if (invoked instanceof GrReferenceExpression) {
for (GroovyResolveResult resolveResult : resolveResults) {
PsiElement resolved = resolveResult.getElement();
PsiType returnType = null;
- if (resolved instanceof PsiMethod && !GroovyPsiManager.getInstance(resolved.getProject()).isTypeBeingInferred(resolved)) {
+ if (resolved instanceof PsiMethod && !GroovyPsiManager.isTypeBeingInferred(resolved)) {
PsiMethod method = (PsiMethod) resolved;
returnType = getClosureCallOrCurryReturnType(callExpression, refExpr, method);
if (returnType == null) {
PsiType refType = refExpr.getType();
final PsiType type = refType == null ? ((GrVariable) resolved).getTypeGroovy() : refType;
if (type instanceof GrClosureType) {
- returnType = ((GrClosureType) type).getClosureReturnType();
+ returnType = ((GrClosureType) type).getSignature().getReturnType();
}
}
if (returnType == null) return null;
@Nullable
private static PsiType getClosureCallOrCurryReturnType(GrMethodCallExpressionImpl callExpression,
- GrReferenceExpression refExpr, PsiMethod resolved) {
+ GrReferenceExpression refExpr,
+ PsiMethod resolved) {
PsiClass clazz = resolved.getContainingClass();
if (clazz != null && GrClosableBlock.GROOVY_LANG_CLOSURE.equals(clazz.getQualifiedName())) {
if ("call".equals(resolved.getName()) || "curry".equals(resolved.getName())) {
PsiType qType = qualifier.getType();
if (qType instanceof GrClosureType) {
if ("call".equals(resolved.getName())) {
- return ((GrClosureType) qType).getClosureReturnType();
- } else if ("curry".equals(resolved.getName())) {
- return ((GrClosureType) qType).curry(callExpression.getExpressionArguments().length);
+ return ((GrClosureType)qType).getSignature().getReturnType();
+ }
+ else if ("curry".equals(resolved.getName())) {
+ return ((GrClosureType)qType).curry(callExpression.getExpressionArguments().length);
}
}
}
return GroovyPsiManager.getInstance(getProject()).getType(this, TYPES_CALCULATOR);
}
+ @Nullable
public GrExpression getInvokedExpression() {
return findChildByClass(GrExpression.class);
}
int refIndex = allArgs.size() - 1;
// New argument list
- GrArgumentList newArgList = GroovyPsiElementFactory.getInstance(getProject()).createExpressionArgumentList(allArgs.toArray(GrExpression.EMPTY_ARRAY));
+ GrArgumentList newArgList =
+ GroovyPsiElementFactory.getInstance(getProject()).createExpressionArgumentList(allArgs.toArray(new GrExpression[allArgs.size()]));
while (closure.getNode().getTreePrev() != null &&
!(closure.getNode().getTreePrev().getPsi() instanceof GrArgumentList)) {
parentNode.removeChild(closure.getNode().getTreePrev());
--- /dev/null
+/*
+ * 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.psi.impl.types;
+
+import com.intellij.openapi.util.Comparing;
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiSubstitutor;
+import com.intellij.psi.PsiType;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class GrClosureParameterImpl implements GrClosureParameter {
+ @Nullable final PsiType myType;
+ @Nullable final String myName=null;
+ final boolean myOptional;
+ @Nullable final GrExpression myDefaultInitializer;
+
+ public GrClosureParameterImpl(/*String name,*/ PsiType type, boolean optional, GrExpression defaultInitializer) {
+// myName = name;
+ myType = type;
+ myOptional = optional;
+ if (myOptional) {
+ myDefaultInitializer = defaultInitializer;
+ }
+ else {
+ myDefaultInitializer = null;
+ }
+ }
+
+ public GrClosureParameterImpl(@Nullable PsiType type) {
+ this(/*null,*/ type, false, null);
+ }
+
+ public GrClosureParameterImpl(PsiParameter parameter) {
+ this(parameter, PsiSubstitutor.EMPTY);
+ }
+
+ public GrClosureParameterImpl(PsiParameter parameter, PsiSubstitutor substitutor) {
+ this(/*parameter.getName(), */substitutor.substitute(parameter.getType()),
+ parameter instanceof GrParameter ? ((GrParameter)parameter).isOptional() : false,
+ parameter instanceof GrParameter ? ((GrParameter)parameter).getDefaultInitializer() : null);
+ }
+
+
+ @Nullable
+ public PsiType getType() {
+ return myType;
+ }
+
+ public boolean isOptional() {
+ return myOptional;
+ }
+
+ @Nullable
+ public GrExpression getDefaultInitializer() {
+ return myDefaultInitializer;
+ }
+
+ public boolean isValid() {
+ return (myType == null || myType.isValid()) && (myDefaultInitializer == null || myDefaultInitializer.isValid());
+ }
+
+ @Nullable
+ public String getName() {
+ return myName;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GrClosureParameter) {
+ return Comparing.equal(myType, ((GrClosureParameter)obj).getType()) &&
+ Comparing.equal(myOptional, ((GrClosureParameter)obj).isOptional()) &&
+ Comparing.equal(myDefaultInitializer, ((GrClosureParameter)obj).getDefaultInitializer());
+ }
+ return super.equals(obj);
+ }
+}
--- /dev/null
+/*
+ * 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.psi.impl.types;
+
+import com.intellij.openapi.util.Comparing;
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
+import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class GrClosureSignatureImpl implements GrClosureSignature {
+ private final boolean myIsVarargs;
+ private final PsiType myReturnType;
+ private final GrClosureParameter[] myParameters;
+
+ public GrClosureSignatureImpl(PsiParameter[] parameters, PsiType returnType, PsiSubstitutor substitutor) {
+ myReturnType = substitutor.substitute(returnType);
+ final int length = parameters.length;
+ myParameters = new GrClosureParameter[length];
+ for (int i = 0; i < length; i++) {
+ myParameters[i] = new GrClosureParameterImpl(parameters[i], substitutor);
+ }
+ if (length > 0) {
+ myIsVarargs = parameters[length - 1].isVarArgs() || myParameters[length - 1].getType() instanceof PsiArrayType;
+ }
+ else {
+ myIsVarargs = false;
+ }
+ }
+
+ public GrClosureSignatureImpl(PsiParameter[] parameters, PsiType returnType) {
+ this(parameters, returnType, PsiSubstitutor.EMPTY);
+ }
+
+ public GrClosureSignatureImpl(PsiParameter[] parameters) {
+ this(parameters, null);
+ }
+
+ public GrClosureSignatureImpl(GrClosableBlock block) {
+ this(block.getAllParameters(), block.getReturnType());
+ }
+
+ public GrClosureSignatureImpl(PsiMethod method) {
+ this(method, PsiSubstitutor.EMPTY);
+ }
+
+ public GrClosureSignatureImpl(PsiMethod method, PsiSubstitutor substitutor) {
+ this(method.getParameterList().getParameters(), method.getReturnType(), substitutor);
+ }
+
+ private GrClosureSignatureImpl(GrClosureParameter[] params, PsiType returnType, boolean isVarArgs) {
+ myParameters = params;
+ myReturnType = returnType;
+ myIsVarargs = isVarArgs;
+ }
+
+
+ public boolean isVarargs() {
+ return myIsVarargs;
+ }
+
+
+ public PsiType getReturnType() {
+ return myReturnType;
+ }
+
+ @NotNull
+ public GrClosureParameter[] getParameters() {
+ GrClosureParameter[] result = new GrClosureParameter[myParameters.length];
+ System.arraycopy(myParameters, 0, result, 0, myParameters.length);
+ return result;
+ }
+
+ public GrClosureSignature curry(int count) {
+ if (count > myParameters.length) {
+ if (isVarargs()) {
+ return new GrClosureSignatureImpl(GrClosureParameter.EMPTY_ARRAY, myReturnType);
+ }
+ else {
+ return null;
+ }
+ }
+ GrClosureParameter[] newParams = new GrClosureParameter[myParameters.length - count];
+ System.arraycopy(myParameters, count, newParams, 0, newParams.length);
+ return new GrClosureSignatureImpl(newParams, myReturnType, myIsVarargs);
+ }
+
+ public boolean isValid() {
+ for (GrClosureParameter parameter : myParameters) {
+ if (!parameter.isValid()) return false;
+ }
+ return myReturnType == null || myReturnType.isValid();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GrClosureSignature) {
+ return Comparing.equal(myParameters, ((GrClosureSignature)obj).getParameters()) &&
+ Comparing.equal(myIsVarargs, ((GrClosureSignature)obj).isVarargs()) &&
+ Comparing.equal(myReturnType, ((GrClosureSignature)obj).getReturnType());
+ }
+ return super.equals(obj);
+ }
+
+ @Nullable
+ public static GrClosureSignature getLeastUpperBound(GrClosureSignature signature1, GrClosureSignature signature2, PsiManager manager) {
+ GrClosureParameter[] parameters1 = signature1.getParameters();
+ GrClosureParameter[] parameters2 = signature2.getParameters();
+
+ if (parameters1.length == parameters2.length) {
+ GrClosureParameter[] params = new GrClosureParameter[parameters1.length];
+ for (int i = 0; i < params.length; i++) {
+ final PsiType type = GenericsUtil.getGreatestLowerBound(parameters1[i].getType(), parameters2[i].getType());
+ boolean opt = parameters1[i].isOptional() && parameters2[i].isOptional();
+ params[i] = new GrClosureParameterImpl(/*null, */type, opt, null);
+ }
+ PsiType returnType = TypesUtil.getLeastUpperBound(signature1.getReturnType(), signature2.getReturnType(), manager);
+ boolean isVarArgs = signature1.isVarargs() && signature2.isVarargs();
+ return new GrClosureSignatureImpl(params, returnType, isVarArgs);
+ }
+ return null; //todo
+ }
+}
+
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashSet;
import gnu.trove.TIntStack;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
+import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
boolean isInUseCategory) {
if (argumentTypes == null) return true;
- PsiParameter[] parameters = method.getParameterList().getParameters();
- if (isInUseCategory && method.hasModifierProperty(PsiModifier.STATIC) && parameters.length > 0) {
- //do not check first parameter, it is 'this' inside categorized block
- parameters = ArrayUtil.remove(parameters, 0);
+ GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, substitutor);
+ if (isInUseCategory && method.hasModifierProperty(PsiModifier.STATIC) && method.getParameterList().getParametersCount() > 0) {
+ signature.curry(1);
}
+ return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, method.getManager(), method.getResolveScope());
+ }
- if (parameters.length == 0) return argumentTypes.length == 0;
-
- final PsiParameter lastParameter = parameters[parameters.length - 1];
- boolean hasVarArgs = lastParameter.isVarArgs() || lastParameter.getType() instanceof PsiArrayType;
- if (!hasVarArgs && argumentTypes.length > parameters.length) return false;
-
- int allOptionalParameterCount = 0;
- for (PsiParameter parameter : parameters) {
- if (isOptionalParameter(parameter)) {
- allOptionalParameterCount++;
- }
- }
-
- int optionalParameterCount;
- if (hasVarArgs) {
- optionalParameterCount = allOptionalParameterCount - (parameters.length - 1) + argumentTypes.length;
- if (optionalParameterCount < 0) return false;
- for (int i = optionalParameterCount; i >= 0; i--) {
- if (checkMethodApplicability(parameters, argumentTypes, i, hasVarArgs, substitutor, method.getResolveScope(), method.getManager())) {
- return true;
- }
- }
- return false;
- }
- else {
- optionalParameterCount = allOptionalParameterCount - parameters.length + argumentTypes.length;
- if (optionalParameterCount < 0) return false;
- return checkMethodApplicability(parameters, argumentTypes, optionalParameterCount, hasVarArgs, substitutor, method.getResolveScope(),
- method.getManager());
-
- }
+ public static boolean isApplicable(@Nullable PsiType[] argumentTypes, GrClosureType type, PsiManager manager) {
+ GrClosureSignature signature = type.getSignature();
+ return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, manager, type.getResolveScope());
}
private static boolean checkMethodApplicability(PsiParameter[] parameters,
for (GrExpression arg : args) {
PsiType argType = getArgumentType(arg);
if (argType == null) {
- result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject((GroovyPsiElement)parent));
+ result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject(parent));
}
else {
result.add(argType);
return expr instanceof GrReferenceExpression || expr instanceof GrIndexProperty || expr instanceof GrPropertySelection;
}
- public static PsiType[] skipOptionalClosureParameters(int argsNum, GrClosureType closureType) {
- PsiType[] parameterTypes = closureType.getClosureParameterTypes();
- int diff = parameterTypes.length - argsNum;
- List<PsiType> result = new ArrayList<PsiType>(argsNum);
- for (int i = 0; i < parameterTypes.length; i++) {
- PsiType type = parameterTypes[i];
- if (diff > 0 && closureType.isOptionalParameter(i)) {
- diff--;
- continue;
- }
-
- result.add(type);
- }
-
- return result.toArray(new PsiType[result.size()]);
- }
-
public static boolean isRawMethodCall(GrMethodCallExpression call) {
final GroovyResolveResult[] resolveResults = call.getMethodVariants();
if (resolveResults.length == 0) return false;
public void testEverythingAssignableToString() throws Exception {doTest(new GroovyAssignabilityCheckInspection());}
public void testMethodCallWithDefaultParameters() throws Exception {doTest();}
+ public void testClosureWithDefaultParameters() throws Exception {doTest();}
public void testOverlyLongMethodInspection() throws Exception {
doTest(new GroovyOverlyLongMethodInspection());
--- /dev/null
+def createRegisteredPerson = {String username,
+ String password,
+ String email,
+ String ipAddress,
+ String roleName = null,
+ String firstName = null,
+ String lastName = null,
+ Date birthday = null,
+ String bio = null,
+ String homepage = null,
+ Date timeZone = null,
+ String country = null,
+ String city = null,
+ String jabber = null,
+ String site = null,
+ String sex = null ->
+}
+
+createRegisteredPerson('name', 'pswd', 'email', 'ip', 'role', 'firstName', 'lastName', null, 'bio', 'page')
+
+def foo(String a, Date b = null, int i = -1, String c, String d = 'd', String e, String f) {}
+
+
+foo('aa', 'cc', 'dd', 'ee')
+foo('a', null, 'c', 'e')
+foo('a', null, 'd', 'c', 'e')
+
+foo<warning descr="'foo' in 'ClosureWithDefaultParameters' cannot be applied to '(java.lang.String, null, java.lang.Integer, java.lang.String, java.lang.String)'">('a', null, 1, 'c', 'e')</warning>
+foo<warning descr="'foo' in 'ClosureWithDefaultParameters' cannot be applied to '(java.lang.String, java.lang.String, java.lang.String)'">("aa", 'cc', 'ee')</warning>
+
+foo('aa', null, 'cc', 'dd', 'ee')
+foo<warning descr="'foo' in 'ClosureWithDefaultParameters' cannot be applied to '(java.lang.String, null, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)'">('aa', null, 1, 'cc', 'dd', 'ee', 'f', 'g')</warning>
+
+foo('a', 'cc', 'dd', 'ee')
+foo<warning descr="'foo' in 'ClosureWithDefaultParameters' cannot be applied to '(java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String)'">('a', - 1, 'cc', 'dd', 'ee')</warning>
+
+
+def bar = {String a, Date b = null, int i = -1, String c, String d = 'd', String e, String ... f ->}
+
+
+bar('aa', 'cc', 'dd', 'ee')
+bar('a', null, 'c', 'e')
+bar('a', null, 'd', 'c', 'e')
+
+bar('a', null, 1, 'c', 'e')
+bar("aa", 'cc', 'ee')
+
+bar('aa', null, 'cc', 'dd', 'ee')
+bar('aa', null, 1, 'cc', 'dd', 'ee', 'f', 'g')
+
+bar('a', 'cc', 'dd', 'ee')
+bar<warning descr="'bar' cannot be applied to '(java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String)'">('a', - 1, 'cc', 'dd', 'ee')</warning>
+
+def go(String a, String b = 'b', String c, int ... i) {}
+
+go('a', 'c', 1, 2, 3);
\ No newline at end of file
-List l=new ArrayList();
+class Arr<T>{
+ void add(T item) {}
+ T get(int i){}
+}
+Arr l=new Arr();
l.add("abc");
Date s=<warning descr="Cannot assign 'Object' to 'Date'">l.get(0)</warning>;
\ No newline at end of file