mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
Disable lambda2methodref if lambda parameter has annotations; preserve annotations in extract to methodref
Fixes IDEA-200489 Replacing lambda with method reference discards annotation on Java 11 var lambda parameter GitOrigin-RevId: 78bf5f00389f8e1e8a866fbaa226cea2e31b749c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fc3d01378e
commit
8ddeb2cd07
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationTargetUtil;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -1100,15 +1101,25 @@ public class LambdaUtil {
|
||||
if (parameters.length != lambdaParameters.length) return null;
|
||||
final PsiSubstitutor substitutor = getSubstitutor(interfaceMethod, resolveResult);
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
PsiType psiType = substitutor.substitute(parameters[i].getType());
|
||||
if (psiType == null) return null;
|
||||
if (!PsiTypesUtil.isDenotableType(psiType, lambdaExpression)) {
|
||||
return null;
|
||||
PsiParameter lambdaParameter = lambdaParameters[i];
|
||||
PsiTypeElement origTypeElement = lambdaParameter.getTypeElement();
|
||||
|
||||
PsiType psiType;
|
||||
if (origTypeElement != null && !origTypeElement.isInferredType()) {
|
||||
psiType = origTypeElement.getType();
|
||||
} else {
|
||||
psiType = substitutor.substitute(parameters[i].getType());
|
||||
if (psiType == null || !PsiTypesUtil.isDenotableType(psiType, lambdaExpression)) return null;
|
||||
}
|
||||
|
||||
buf.append(checkApplicability ? psiType.getPresentableText() : psiType.getCanonicalText())
|
||||
PsiAnnotation[] annotations = lambdaParameter.getAnnotations();
|
||||
for (PsiAnnotation annotation : annotations) {
|
||||
if (AnnotationTargetUtil.isTypeAnnotation(annotation)) continue;
|
||||
buf.append(annotation.getText()).append(' ');
|
||||
}
|
||||
buf.append(checkApplicability ? psiType.getPresentableText(true) : psiType.getCanonicalText(true))
|
||||
.append(" ")
|
||||
.append(lambdaParameters[i].getName());
|
||||
.append(lambdaParameter.getName());
|
||||
if (i < parameters.length - 1) {
|
||||
buf.append(", ");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Replace lambda with method reference" "false"
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class Test {
|
||||
Consumer<Integer> c = (@Nonnull Integer i) -> System<caret>.out.println(i);
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
private static final Logger LOG = Logger.getInstance(LambdaCanBeMethodReferenceInspection.class);
|
||||
@@ -106,6 +107,8 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
|
||||
@Nullable PsiElement context,
|
||||
final PsiExpression methodRefCandidate) {
|
||||
if (functionalInterfaceType == null) return null;
|
||||
// Do not suggest for annotated lambda, as annotation will be lost during the conversion
|
||||
if (Stream.of(parameters).anyMatch(LambdaCanBeMethodReferenceInspection::hasAnnotation)) return null;
|
||||
if (methodRefCandidate instanceof PsiNewExpression) {
|
||||
final PsiNewExpression newExpression = (PsiNewExpression)methodRefCandidate;
|
||||
if (newExpression.getAnonymousClass() != null || newExpression.getArrayInitializer() != null) {
|
||||
@@ -574,6 +577,17 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p variable to test
|
||||
* @return true if given variable is annotated or its type is annotated
|
||||
*/
|
||||
private static boolean hasAnnotation(PsiVariable p) {
|
||||
if (p.getAnnotations().length > 0) return true;
|
||||
PsiTypeElement typeElement = p.getTypeElement();
|
||||
return typeElement != null && !typeElement.isInferredType() &&
|
||||
!typeElement.getType().getCanonicalText(true).equals(typeElement.getType().getCanonicalText(false));
|
||||
}
|
||||
|
||||
private static class ReplaceWithMethodRefFix implements LocalQuickFix {
|
||||
private final String mySuffix;
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class X {
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer> c1 = (@AAA Integer<caret> i) -> System.out.println(i);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.function.Consumer;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class X {
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER})
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer[]> c1 = (@AAA Integer<caret> @AAA [] i) -> System.out.println(i);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.function.Consumer;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class X {
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER})
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer[]> c1 = (Integer<caret> @AAA [] i) -> System.out.println(i);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.util.function.Consumer;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class X {
|
||||
private static void accept(Integer @AAA [] i) {
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER})
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer[]> c1 = X::<caret>accept;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.util.function.Consumer;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class X {
|
||||
private static void accept(@AAA Integer @AAA [] i) {
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER})
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer[]> c1 = X::<caret>accept;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.function.Consumer;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class X {
|
||||
@Target(ElementType.PARAMETER)
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer[]> c1 = (@AAA var<caret> i) -> System.out.println(i);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.util.function.Consumer;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
class X {
|
||||
private static void accept(@AAA Integer[] i) {
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
@Target(ElementType.PARAMETER)
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer[]> c1 = X::<caret>accept;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class X {
|
||||
private static void accept(@AAA Integer i) {
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
@interface AAA {}
|
||||
|
||||
Consumer<Integer> c1 = X::<caret>accept;
|
||||
}
|
||||
@@ -65,6 +65,22 @@ public class ExtractToMethodReferenceTest extends IPPTestCase {
|
||||
public void testUsedLocalVariables() {
|
||||
assertIntentionNotAvailable();
|
||||
}
|
||||
|
||||
public void testAnnotatedLambdaParameter() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAnnotatedLambdaParameterType() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAnnotatedLambdaParameterType2() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAnnotatedLambdaParameterVar() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIntentionName() {
|
||||
@@ -79,7 +95,7 @@ public class ExtractToMethodReferenceTest extends IPPTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return JAVA_8;
|
||||
return JAVA_11;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user