diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 075f1a5f4032..3a737880f10a 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -127,6 +127,7 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java index 6b9f4a2d19cc..457c98406cf0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java @@ -114,7 +114,7 @@ public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnh } @Nullable - private static PsiType getSingleMethodParameterType(@Nullable PsiType type, int index, GrClosableBlock closure) { + public static PsiType getSingleMethodParameterType(@Nullable PsiType type, int index, GrClosableBlock closure) { final PsiType[] signature = findSingleAbstractMethodSignature(type); if (signature != null && GrClosureSignatureUtil.isSignatureApplicable(GrClosureSignatureUtil.createSignature(closure), signature, closure)) { return signature.length > index ? signature[index] : PsiType.NULL; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java index a3f84e14109c..d36faf97e26a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java @@ -76,7 +76,7 @@ public class GppTypeConverter extends GrTypeConverter { return true; } } - else if (rType instanceof GrClosureType) { + else if (rType instanceof GrClosureType && hasTypedContext(context)) { final PsiType[] methodParameters = GppClosureParameterTypeProvider.findSingleAbstractMethodSignature(lType); if (isClosureOverride(methodParameters, (GrClosureType)rType, context)) return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java new file mode 100644 index 000000000000..6ebe35af596f --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2012 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.typeEnhancers; + +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiType; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.gpp.GppClosureParameterTypeProvider; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSafeCastExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Max Medvedev + */ +public class ClosureAsAnonymousParameterEnhancer extends AbstractClosureParameterEnhancer { + @Nullable + @Override + protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { + + Set expectedTypes; + + if (closure.getParent() instanceof GrSafeCastExpression) { + GrSafeCastExpression safeCastExpression = (GrSafeCastExpression)closure.getParent(); + GrTypeElement typeElement = safeCastExpression.getCastTypeElement(); + if (typeElement != null) { + PsiType castType = typeElement.getType(); + expectedTypes = new HashSet(GroovyExpectedTypesProvider.getDefaultExpectedTypes(safeCastExpression)); + PsiManager manager = closure.getManager(); + GlobalSearchScope scope = closure.getResolveScope(); + for (PsiType expected : expectedTypes) { + if (!TypesUtil.isAssignable(expected, castType, manager, scope)) { + expectedTypes.remove(expected); + } + } + + if (expectedTypes.isEmpty()) expectedTypes.add(castType); + } + else { + expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); + } + } + else { + expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); + } + + for (PsiType constraint : expectedTypes) { + final PsiType suggestion = GppClosureParameterTypeProvider.getSingleMethodParameterType(constraint, index, closure); + if (suggestion != null) { + return suggestion; + } + } + + return null; + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index 6dfb40b48c7d..f973bd3303ac 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -1452,6 +1452,25 @@ List foo() {[]} def (int x, String y) = foo() List foo() {[]} +''', GroovyAssignabilityCheckInspection) + } + + void testCastClosureToInterface() { + testHighlighting('''\ +interface Function { + F fun(D d) +} + +def foo(Function function) { + // print function.fun('abc') +} + + +foo({println it.byteValue()} as Function) +foo({println it.substring(1)} as Function) +foo({println it.substring(1)} as Function) +foo({println it}) + ''', GroovyAssignabilityCheckInspection) }