diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index ffbacaad7f08..46175c5d55a5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -625,9 +625,17 @@ public class AnnotationsHighlightUtil { @Nullable public static HighlightInfo checkFunctionalInterface(@NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel) { - final String errorMessage = LambdaUtil.checkFunctionalInterface(annotation, languageLevel); - if (errorMessage != null) { - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotation).descriptionAndTooltip(errorMessage).create(); + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && Comparing.strEqual(annotation.getQualifiedName(), CommonClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE)) { + final PsiAnnotationOwner owner = annotation.getOwner(); + if (owner instanceof PsiModifierList) { + final PsiElement parent = ((PsiModifierList)owner).getParent(); + if (parent instanceof PsiClass) { + final String errorMessage = LambdaHighlightingUtil.checkInterfaceFunctional((PsiClass)parent, ((PsiClass)parent).getName() + " is not a functional interface"); + if (errorMessage != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotation).descriptionAndTooltip(errorMessage).create(); + } + } + } } return null; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index b6e42f0b6cbd..895d0e65570b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -319,7 +319,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder.add(result); //todo[ann] append not inferred type params info } else { - final String incompatibleReturnTypesMessage = LambdaHighlightingUtil + final String incompatibleReturnTypesMessage = LambdaUtil .checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType)); if (incompatibleReturnTypesMessage != null) { final List returnExpressions = LambdaUtil.getReturnExpressions(expression); diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/LambdaHighlightingUtil.java similarity index 73% rename from java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java rename to java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/LambdaHighlightingUtil.java index fa3a7290b861..88950285d43b 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaHighlightingUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/LambdaHighlightingUtil.java @@ -13,17 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi; +package com.intellij.codeInsight.daemon.impl.analysis; -import com.intellij.openapi.util.Computable; +import com.intellij.psi.*; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import sun.plugin2.message.JavaScriptEvalMessage; import java.util.List; @@ -76,41 +74,6 @@ public class LambdaHighlightingUtil { return null; } - public static String checkReturnTypeCompatible(PsiLambdaExpression lambdaExpression, PsiType functionalInterfaceReturnType) { - if (functionalInterfaceReturnType == PsiType.VOID) { - final PsiElement body = lambdaExpression.getBody(); - if (body instanceof PsiCodeBlock) { - if (!LambdaUtil.getReturnExpressions(lambdaExpression).isEmpty()) return "Unexpected return value"; - } else if (body instanceof PsiExpression) { - final PsiType type = ((PsiExpression)body).getType(); - try { - if (!PsiUtil.isStatement(JavaPsiFacade.getElementFactory(body.getProject()).createStatementFromText(body.getText(), body))) { - return "Bad return type in lambda expression: " + (type == PsiType.NULL || type == null ? "" : type.getPresentableText()) + " cannot be converted to void"; - } - } - catch (IncorrectOperationException ignore) { - } - } - } else if (functionalInterfaceReturnType != null) { - final List returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression); - for (final PsiExpression expression : returnExpressions) { - final PsiType expressionType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, true, new Computable() { - @Override - public PsiType compute() { - return expression.getType(); - } - }); - if (expressionType != null && !functionalInterfaceReturnType.isAssignableFrom(expressionType)) { - return "Bad return type in lambda expression: " + expressionType.getPresentableText() + " cannot be converted to " + functionalInterfaceReturnType.getPresentableText(); - } - } - if (LambdaUtil.getReturnStatements(lambdaExpression).length > returnExpressions.size() || returnExpressions.isEmpty() && !lambdaExpression.isVoidCompatible()) { - return "Missing return value"; - } - } - return null; - } - public static boolean insertSemicolonAfter(PsiLambdaExpression lambdaExpression) { if (lambdaExpression.getBody() instanceof PsiCodeBlock) { return true; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index 0266b905186a..f1a601117e62 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; +import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index dd66d54a9d76..8b8fcd40619f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight; +import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java index 8c1e9a5fc980..7ab087b78b8f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 96a00bd98b10..4402a4e27784 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.completion.scope.CompletionElement; import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; +import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.codeInsight.guess.GuessManager; import com.intellij.codeInsight.lookup.*; import com.intellij.codeInspection.java15api.Java15APIUsageInspectionBase; diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 8f072b7853e9..954dd08703c9 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.*; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -140,7 +141,7 @@ public class LambdaUtil { } @Nullable - static MethodSignature getFunction(PsiClass psiClass) { + public static MethodSignature getFunction(PsiClass psiClass) { if (psiClass == null) return null; final List functions = findFunctionCandidates(psiClass); if (functions != null && functions.size() == 1) { @@ -440,20 +441,6 @@ public class LambdaUtil { return result; } - @Nullable - public static String checkFunctionalInterface(@NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel) { - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && Comparing.strEqual(annotation.getQualifiedName(), CommonClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE)) { - final PsiAnnotationOwner owner = annotation.getOwner(); - if (owner instanceof PsiModifierList) { - final PsiElement parent = ((PsiModifierList)owner).getParent(); - if (parent instanceof PsiClass) { - return LambdaHighlightingUtil.checkInterfaceFunctional((PsiClass)parent, ((PsiClass)parent).getName() + " is not a functional interface"); - } - } - } - return null; - } - public static boolean isValidQualifier4InterfaceStaticMethodCall(@NotNull PsiMethod method, @NotNull PsiReferenceExpression methodReferenceExpression, @Nullable PsiElement scope, @NotNull LanguageLevel languageLevel) { @@ -554,6 +541,41 @@ public class LambdaUtil { return map; } + public static String checkReturnTypeCompatible(PsiLambdaExpression lambdaExpression, PsiType functionalInterfaceReturnType) { + if (functionalInterfaceReturnType == PsiType.VOID) { + final PsiElement body = lambdaExpression.getBody(); + if (body instanceof PsiCodeBlock) { + if (!getReturnExpressions(lambdaExpression).isEmpty()) return "Unexpected return value"; + } else if (body instanceof PsiExpression) { + final PsiType type = ((PsiExpression)body).getType(); + try { + if (!PsiUtil.isStatement(JavaPsiFacade.getElementFactory(body.getProject()).createStatementFromText(body.getText(), body))) { + return "Bad return type in lambda expression: " + (type == PsiType.NULL || type == null ? "" : type.getPresentableText()) + " cannot be converted to void"; + } + } + catch (IncorrectOperationException ignore) { + } + } + } else if (functionalInterfaceReturnType != null) { + final List returnExpressions = getReturnExpressions(lambdaExpression); + for (final PsiExpression expression : returnExpressions) { + final PsiType expressionType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, true, new Computable() { + @Override + public PsiType compute() { + return expression.getType(); + } + }); + if (expressionType != null && !functionalInterfaceReturnType.isAssignableFrom(expressionType)) { + return "Bad return type in lambda expression: " + expressionType.getPresentableText() + " cannot be converted to " + functionalInterfaceReturnType.getPresentableText(); + } + } + if (getReturnStatements(lambdaExpression).length > returnExpressions.size() || returnExpressions.isEmpty() && !lambdaExpression.isVoidCompatible()) { + return "Missing return value"; + } + } + return null; + } + public static class TypeParamsChecker extends PsiTypeVisitor { private PsiMethod myMethod; private final PsiClass myClass; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java index 2102c8a373f2..83b0dcf9474d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java @@ -33,7 +33,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.HashMap; import java.util.Map; public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements PsiLambdaExpression { @@ -231,7 +230,7 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi if (map.put(this, leftType) != null) { return false; } - return LambdaHighlightingUtil.checkReturnTypeCompatible(this, substitutor.substitute(methodReturnType)) == null; + return LambdaUtil.checkReturnTypeCompatible(this, substitutor.substitute(methodReturnType)) == null; } finally { map.remove(this); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalInterfaceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalInterfaceTest.java index 8eaf7c316b5f..04172ae858d3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalInterfaceTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalInterfaceTest.java @@ -16,7 +16,7 @@ package com.intellij.codeInsight.daemon.lambda; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; -import com.intellij.psi.LambdaHighlightingUtil; +import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NonNls; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java index 3de34fba65c2..5bbfa11528ac 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CollectionQueryUpdateCalledVisitor.java @@ -15,6 +15,7 @@ */ package com.siyeh.ig.bugs; +import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.ContainerUtil; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java index a8bd19523cad..8d19a88e0592 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/InterfaceMayBeAnnotatedFunctionalInspection.java @@ -16,6 +16,7 @@ package com.siyeh.ig.classlayout; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; import com.intellij.psi.*; import com.intellij.psi.util.MethodSignature;