diff --git a/java/java-impl-refactorings/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java b/java/java-impl-refactorings/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java index 4fff6383e6aa..aebe18bf9fe2 100644 --- a/java/java-impl-refactorings/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java +++ b/java/java-impl-refactorings/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java @@ -73,6 +73,14 @@ public final class ExtractToMethodReferenceIntention extends BaseElementAtCaretI return false; } + //not directly inside an implicitly declared class + PsiClass targetClass = PsiUtil.getContainingClass(lambdaExpression); + PsiMethod method = PsiTreeUtil.getParentOfType(lambdaExpression, PsiMethod.class, true); + if (targetClass == null || + (targetClass instanceof PsiImplicitClass && method != null && method.hasModifierProperty(PsiModifier.STATIC))) { + return false; + } + PsiExpression asMethodReference = LambdaCanBeMethodReferenceInspection .canBeMethodReferenceProblem(body, lambdaExpression.getParameterList().getParameters(), functionalInterfaceType, null); if (asMethodReference != null) return false; @@ -82,8 +90,7 @@ public final class ExtractToMethodReferenceIntention extends BaseElementAtCaretI wrapper.prepareAndCheckExitStatements(toExtract, body); PsiVariable[] outputVariables = wrapper.getOutputVariables(); List inputVariables = wrapper.getInputVariables(body, toExtract, outputVariables); - return inputVariables.stream() - .allMatch(variable -> variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() == lambdaExpression); + return ContainerUtil.and(inputVariables, variable -> variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() == lambdaExpression); } catch (PrepareFailedException | ControlFlowWrapper.ExitStatementsNotSameException ignored) { } @@ -102,7 +109,8 @@ public final class ExtractToMethodReferenceIntention extends BaseElementAtCaretI PsiElement[] elements = body.getStatements(); HashSet usedFields = new HashSet<>(); - boolean canBeStatic = CommonJavaRefactoringUtil.canBeStatic(targetClass, lambdaExpression, elements, usedFields) && usedFields.isEmpty(); + boolean canBeStatic = CommonJavaRefactoringUtil.canBeStatic(targetClass, lambdaExpression, elements, usedFields) && + usedFields.isEmpty() && !(targetClass instanceof PsiImplicitClass); PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(targetClass.getProject()); PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType(); @@ -144,7 +152,7 @@ public final class ExtractToMethodReferenceIntention extends BaseElementAtCaretI PsiIdentifier nameIdentifier = method.getNameIdentifier(); if (nameIdentifier == null) return; nameIdentifier = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(nameIdentifier); - + if (nameIdentifier == null) return; //try to navigate to reference name editor.getCaretModel().moveToOffset(ObjectUtils.notNull(methodReference.getReferenceNameElement(), nameIdentifier).getTextOffset()); diff --git a/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/LambdaInImplicitClass.java b/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/LambdaInImplicitClass.java new file mode 100644 index 000000000000..42ac1f77c017 --- /dev/null +++ b/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/LambdaInImplicitClass.java @@ -0,0 +1,15 @@ +void main(String[] args) throws IOException { + List.of("1").forEach(line -> { + Person person = new Person(line); + IO.println(person); + }); +} + +private record Person(String name) { + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/LambdaInImplicitClass_after.java b/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/LambdaInImplicitClass_after.java new file mode 100644 index 000000000000..11e1df887443 --- /dev/null +++ b/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/LambdaInImplicitClass_after.java @@ -0,0 +1,17 @@ +void main(String[] args) throws IOException { + List.of("1").forEach(this::accept); +} + +private record Person(String name) { + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + '}'; + } +} + +private void accept(String line) { + Person person = new Person(line); + IO.println(person); +} diff --git a/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/StaticLambdaInImplicitClass.java b/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/StaticLambdaInImplicitClass.java new file mode 100644 index 000000000000..f4ee56bd879f --- /dev/null +++ b/java/java-tests/testData/ipp/com/siyeh/ipp/functional/extractToMethodReference/StaticLambdaInImplicitClass.java @@ -0,0 +1,15 @@ +static void main(String[] args) throws IOException { + List.of("1").forEach(line -> { + Person person = new Person(line); + IO.println(person); + }); +} + +private record Person(String name) { + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/java/java-tests/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java b/java/java-tests/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java index 9fe43de28d78..453c45fb448d 100644 --- a/java/java-tests/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java +++ b/java/java-tests/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java @@ -15,6 +15,8 @@ */ package com.siyeh.ipp.functional; +import com.intellij.pom.java.JavaFeature; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.LightProjectDescriptor; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ipp.IPPTestCase; @@ -86,6 +88,14 @@ public class ExtractToMethodReferenceTest extends IPPTestCase { doTest(); } + public void testLambdaInImplicitClass() { + IdeaTestUtil.withLevel(getModule(), JavaFeature.IMPLICIT_CLASSES.getStandardLevel(), this::doTest); + } + + public void testStaticLambdaInImplicitClass() { + IdeaTestUtil.withLevel(getModule(), JavaFeature.IMPLICIT_CLASSES.getStandardLevel(), this::assertIntentionNotAvailable); + } + @Override protected String getIntentionName() { return IntentionPowerPackBundle.message("extract.to.method.reference.intention.name");