new GrClosureType & highlighting for closures
authorMaxim Medvedev <maxim.medvedev@jetbrains.com>
Fri, 26 Feb 2010 22:32:08 +0000 (01:32 +0300)
committerMaxim Medvedev <maxim.medvedev@jetbrains.com>
Fri, 26 Feb 2010 22:32:08 +0000 (01:32 +0300)
15 files changed:
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parameterInfo/GroovyParameterInfoHandler.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrClosureParameter.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrClosureSignature.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureSignatureUtil.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/path/GrMethodCallExpressionImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureImpl.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java
plugins/groovy/testdata/highlighting/ClosureWithDefaultParameters.groovy [new file with mode: 0644]
plugins/groovy/testdata/highlighting/RawMethodAccess.groovy

index c681e3cbeaeaaa8dbf49815dd73d8fdf2a7dd152..033a556a92160675a7e3602ac5d822df22bdbc81 100644 (file)
@@ -30,7 +30,6 @@ import com.intellij.openapi.util.text.StringUtil;
 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;
@@ -1286,8 +1285,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
     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);
@@ -1296,19 +1294,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
     }
   }
 
-  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
index a312c60674a0e0f9ae7814bd8d77e829a23b9993..608bd84985d93893a250879d68e381435191d4f6 100644 (file)
@@ -42,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrC
 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;
@@ -228,7 +229,7 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandler<GroovyPs
         if (expr.getTextRange().contains(offset)) return idx;
         idx++;
       }
-    } 
+    }
 
     return -1;
   }
@@ -310,17 +311,30 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandler<GroovyPs
 
     } 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");
         }
       }
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrClosureParameter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrClosureParameter.java
new file mode 100644 (file)
index 0000000..70e763c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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();
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrClosureSignature.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrClosureSignature.java
new file mode 100644 (file)
index 0000000..ada0d0f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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();
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureSignatureUtil.java
new file mode 100644 (file)
index 0000000..39d508a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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;
+  }
+}
index bd756a33c690827db3c56881560c6fb13c95f322..f18a3c7c9fb43e5956062ffa634a2ada08284134 100644 (file)
@@ -24,30 +24,22 @@ import org.jetbrains.annotations.NonNls;
 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
@@ -55,19 +47,6 @@ public class GrClosureType extends PsiClassType {
     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";
   }
@@ -101,6 +80,7 @@ public class GrClosureType extends PsiClassType {
         return true;
       }
 
+      @Nullable
       public PsiElement getCurrentFileResolveScope() {
         return null;
       }
@@ -127,25 +107,18 @@ public class GrClosureType extends PsiClassType {
     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);
@@ -154,14 +127,28 @@ public class GrClosureType extends PsiClassType {
   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;
     }
@@ -183,45 +170,49 @@ public class GrClosureType extends PsiClassType {
   }
 
   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;
   }
 }
index 7ff2441eee21e08925ad7cf56f7347e4db4dff29..add7c09befe3047a9ca747e8bf8099eebb0266de 100644 (file)
@@ -206,9 +206,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
     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());
     }
index 41cf8c4ad425e30b4a2d72f91575e2d3b316ff9b..a176fc19863a378ed03e42601842a8f9623f6def 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.psi.search.GlobalSearchScope;
 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;
@@ -32,8 +33,11 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
 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;
@@ -349,20 +353,17 @@ public class TypesUtil {
     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()) &&
index 39c1f33bf59dfc2b42d40c19c78b4bd8dfc0b04f..da9a0b82f3cfee938ff927ccdf837a85a92a46b9 100644 (file)
@@ -46,6 +46,7 @@ import java.util.Arrays;
  */
 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) {
@@ -57,7 +58,7 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
         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) {
@@ -67,7 +68,7 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
             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;
@@ -94,7 +95,8 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
 
   @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())) {
@@ -103,9 +105,10 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
           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);
             }
           }
         }
@@ -130,6 +133,7 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
     return GroovyPsiManager.getInstance(getProject()).getType(this, TYPES_CALCULATOR);
   }
 
+  @Nullable
   public GrExpression getInvokedExpression() {
     return findChildByClass(GrExpression.class);
   }
@@ -151,7 +155,8 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
       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());
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureParameterImpl.java
new file mode 100644 (file)
index 0000000..1f85871
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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);
+  }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureImpl.java
new file mode 100644 (file)
index 0000000..927bb6f
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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
+  }
+}
+
index 429704116652dbd3ebce37c9ae7764ee6184b15f..c8d7d55475a37b191c4a334b359c0fbf700544d2 100644 (file)
@@ -29,7 +29,6 @@ import com.intellij.psi.search.GlobalSearchScope;
 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;
@@ -66,7 +65,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini
 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;
@@ -124,43 +125,16 @@ public class PsiUtil {
                                      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,
@@ -302,7 +276,7 @@ public class PsiUtil {
       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);
@@ -620,23 +594,6 @@ public class PsiUtil {
     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;
index f5e652e87ca1cb322b2ed622bd38e48d1e18a4b4..7bd8b61e07144ca1839afad8a3c460a543e1e7c9 100644 (file)
@@ -193,6 +193,7 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
   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());
diff --git a/plugins/groovy/testdata/highlighting/ClosureWithDefaultParameters.groovy b/plugins/groovy/testdata/highlighting/ClosureWithDefaultParameters.groovy
new file mode 100644 (file)
index 0000000..1384582
--- /dev/null
@@ -0,0 +1,56 @@
+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
index 0e90b9d140cf7291b35a831250a4ec0555969c89..516e6fc33c553d306690d666aa196fefdd865cea 100644 (file)
@@ -1,3 +1,7 @@
-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