This is an automated email from the ASF dual-hosted git repository. mbien pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push: new b2e0288af6 ConvertToLambda hint should ignore default methods. new 3e5661f4b3 Merge pull request #6658 from mbien/no-lambda-for-default-methods b2e0288af6 is described below commit b2e0288af62653fc59b94cbd336422af30be87b7 Author: Michael Bien <mbie...@gmail.com> AuthorDate: Fri Nov 3 05:55:53 2023 +0100 ConvertToLambda hint should ignore default methods. Default methods don't qualify for functional interfaces since they are not abstract and can therefore not be converted into lambdas. --- .../modules/java/hints/jdk/ConvertToLambda.java | 5 +- .../java/hints/jdk/ConvertToLambdaConverter.java | 3 - .../jdk/ConvertToLambdaPreconditionChecker.java | 33 ++++++++++- .../java/hints/jdk/ConvertToLambdaTest.java | 64 ++++++++++++++++++++++ 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambda.java b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambda.java index 38244c446c..6c134a95af 100644 --- a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambda.java +++ b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambda.java @@ -21,7 +21,6 @@ */ package org.netbeans.modules.java.hints.jdk; -import com.sun.source.tree.ClassTree; import com.sun.source.tree.NewClassTree; import com.sun.source.tree.Tree.Kind; import com.sun.source.util.TreePath; @@ -29,7 +28,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import javax.tools.Diagnostic; import org.netbeans.api.java.source.CompilationInfo; import org.netbeans.api.java.source.JavaSource.Phase; import org.netbeans.api.java.source.WorkingCopy; @@ -56,7 +54,7 @@ import org.openide.util.NbBundle; public class ConvertToLambda { public static final String ID = "Javac_canUseLambda"; //NOI18N - public static final Set<String> CODES = new HashSet<String>(Arrays.asList("compiler.warn.potential.lambda.found")); //NOI18N + public static final Set<String> CODES = new HashSet<>(Arrays.asList("compiler.warn.potential.lambda.found")); //NOI18N static final boolean DEF_PREFER_MEMBER_REFERENCES = true; @@ -68,7 +66,6 @@ public class ConvertToLambda { }) @NbBundle.Messages("MSG_AnonymousConvertibleToLambda=This anonymous inner class creation can be turned into a lambda expression.") public static ErrorDescription computeAnnonymousToLambda(HintContext ctx) { - ClassTree clazz = ((NewClassTree) ctx.getPath().getLeaf()).getClassBody(); ConvertToLambdaPreconditionChecker preconditionChecker = new ConvertToLambdaPreconditionChecker(ctx.getPath(), ctx.getInfo()); if (!preconditionChecker.passesFatalPreconditions()) { diff --git a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaConverter.java b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaConverter.java index ee53aca15c..963ae107fc 100644 --- a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaConverter.java +++ b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaConverter.java @@ -21,7 +21,6 @@ */ package org.netbeans.modules.java.hints.jdk; -import com.sun.source.tree.BlockTree; import com.sun.source.tree.ClassTree; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.IdentifierTree; @@ -48,9 +47,7 @@ import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.ReturnTree; import java.util.List; -import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; -import org.netbeans.api.java.source.CompilationInfo; import org.netbeans.api.java.source.TreeMaker; import org.netbeans.api.java.source.WorkingCopy; import org.netbeans.api.java.source.matching.Matcher; diff --git a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaPreconditionChecker.java b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaPreconditionChecker.java index b13179430c..08abae6e15 100644 --- a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaPreconditionChecker.java +++ b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaPreconditionChecker.java @@ -50,6 +50,8 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import org.netbeans.api.java.source.CompilationInfo; import org.netbeans.api.java.source.TreeUtilities; @@ -64,6 +66,7 @@ public class ConvertToLambdaPreconditionChecker { private final Scope localScope; private final CompilationInfo info; private final Types types; + private final Elements elements; private boolean foundRefToThisOrSuper = false; private boolean foundShadowedVariable = false; private boolean foundRecursiveCall = false; @@ -85,6 +88,7 @@ public class ConvertToLambdaPreconditionChecker { this.newClassTree = (NewClassTree) pathToNewClassTree.getLeaf(); this.info = info; this.types = info.getTypes(); + this.elements = info.getElements(); Element el = info.getTrees().getElement(pathToNewClassTree); if (el != null && el.getKind() == ElementKind.CONSTRUCTOR) { @@ -137,7 +141,32 @@ public class ConvertToLambdaPreconditionChecker { candidate = (MethodTree)member; } } - return candidate; + // only abstract methods can be implemented as lambda (e.g default methods can't) + ExecutableElement candidateElement = (ExecutableElement) info.getTrees().getElement(new TreePath(pathToNewClassTree, candidate)); + if (overridesAbstractMethod(candidateElement, (TypeElement) baseElement)) { + return candidate; + } + return null; + } + + private boolean overridesAbstractMethod(ExecutableElement method, TypeElement superType) { + Boolean overrides = overridesAbstractMethodImpl(method, superType); + return overrides != null && overrides; + } + + private Boolean overridesAbstractMethodImpl(ExecutableElement method, TypeElement superType) { + for (ExecutableElement otherMethod : ElementFilter.methodsIn(superType.getEnclosedElements())) { + if (elements.overrides(method, otherMethod, superType)) { + return otherMethod.getModifiers().contains(Modifier.ABSTRACT); + } + } + for (TypeMirror otherType : superType.getInterfaces()) { + Boolean overrides = overridesAbstractMethodImpl(method, (TypeElement) types.asElement(otherType)); + if (overrides != null) { + return overrides; + } + } + return null; // no match here but check the rest of the interface tree } public boolean passesAllPreconditions() { @@ -716,7 +745,7 @@ public class ConvertToLambdaPreconditionChecker { } private List<TypeMirror> getTypesFromElements(List<? extends VariableElement> elements) { - List<TypeMirror> elementTypes = new ArrayList<TypeMirror>(); + List<TypeMirror> elementTypes = new ArrayList<>(elements.size()); for (Element e : elements) { elementTypes.add(e.asType()); } diff --git a/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaTest.java b/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaTest.java index 3574930aeb..50e21cb05c 100644 --- a/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaTest.java +++ b/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToLambdaTest.java @@ -1101,6 +1101,70 @@ public class ConvertToLambdaTest extends NbTestCase { } + // default methods don't qualify for functional interfaces + public void testThatDefaultMethodsAreIgnored1() throws Exception { + HintTest.create() + .sourceLevel("1.8") + .input("package test;\n" + + "public class Test {\n" + + " private interface NotFunctional {\n" + + " public default void a(int i) {};\n" + + " }\n" + + " NotFunctional nf = new NotFunctional() {\n" + + " @Override public void a(int i) { System.err.println(i); }\n" + + " };\n" + + "}\n") + .run(ConvertToLambda.class) + .assertWarnings(); + } + + public void testThatDefaultMethodsAreIgnored2() throws Exception { + HintTest.create() + .sourceLevel("1.8") + .input("package test;\n" + + "public class Test {\n" + + " private interface DefaultRunnableNotFunctional1 extends Runnable {\n" + + " @Override public default void run() {};\n" + + " }\n" + + " private interface DefaultRunnableNotFunctional2 extends DefaultRunnableNotFunctional1 {}\n" + + " DefaultRunnableNotFunctional2 nf = new DefaultRunnableNotFunctional2() {\n" + + " @Override public void run() { System.err.println(); }\n" + + " };\n" + + "}\n") + .run(ConvertToLambda.class) + .assertWarnings(); + } + + public void testThatDefaultMethodsAreIgnored3() throws Exception { + HintTest.create() + .sourceLevel("1.8") + .input("package test;\n" + + "public class Test {\n" + + " private interface DefaultRunnableFunctional1 extends Runnable {\n" + + " public void walk();\n" + + " @Override public default void run() {};\n" + + " }\n" + + " private interface DefaultRunnableFunctional2 extends DefaultRunnableFunctional1 {}\n" + + " DefaultRunnableFunctional2 f = new DefaultRunnableFunctional2() {\n" + + " @Override public void walk() { System.err.println(5); }\n" + + " };\n" + + "}\n") + .run(ConvertToLambda.class) + .findWarning("7:39-7:65:" + lambdaConvWarning) + .applyFix() + .assertOutput("package test;\n" + + "public class Test {\n" + + " private interface DefaultRunnableFunctional1 extends Runnable {\n" + + " public void walk();\n" + + " @Override public default void run() {};\n" + + " }\n" + + " private interface DefaultRunnableFunctional2 extends DefaultRunnableFunctional1 {}\n" + + " DefaultRunnableFunctional2 f = () -> {\n" + + " System.err.println(5);\n" + + " };\n" + + "}\n"); + } + static { TestCompilerSettings.commandLine = "-XDfind=lambda"; JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true; --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists