diff options
| author | Till Brychcy | 2017-03-19 21:44:22 +0000 |
|---|---|---|
| committer | Stephan Herrmann | 2017-05-06 18:42:50 +0000 |
| commit | d560a31d4a90bee367ebfb27ae5d826d07dc7ac5 (patch) | |
| tree | d41ecbf35283cad7ee658f0e3415e892a5952d63 | |
| parent | 5f557425e79e1e6db303eb89e4a941222e9e8ae0 (diff) | |
| download | eclipse.jdt.ui-d560a31d4a90bee367ebfb27ae5d826d07dc7ac5.tar.gz eclipse.jdt.ui-d560a31d4a90bee367ebfb27ae5d826d07dc7ac5.tar.xz eclipse.jdt.ui-d560a31d4a90bee367ebfb27ae5d826d07dc7ac5.zip | |
Bug 514203 - [quick assist] Lambda: improve handling of wildcards &I20170509-1100I20170509-0945I20170509-0800I20170508-2000I20170508-0800I20170507-2000I20170506-2000
captures and avoid creating redundant @NonNull
Change-Id: I70a371ffa5fa2180b60a9bc976d7d859422b842b
Signed-off-by: Till Brychcy <register.eclipse@brychcy.de>
4 files changed, 659 insertions, 35 deletions
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java index dfa33cf209..154d8cdc4f 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest18.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2016 IBM Corporation and others. + * Copyright (c) 2013, 2017 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -18,6 +18,7 @@ import java.util.List; import org.eclipse.jdt.testplugin.JavaProjectHelper; import org.eclipse.jdt.testplugin.TestOptions; +import org.eclipse.core.runtime.Path; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jdt.core.ICompilationUnit; @@ -4555,4 +4556,625 @@ public class AssistQuickFixTest18 extends QuickFixTest { assertProposalDoesNotExist(proposals, CorrectionMessages.QuickAssistProcessor_removeParenthesesInLambda); } + public void testBug514203_wildCard() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + StringBuffer buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.Comparator;\n"); + buf.append("import java.util.List;\n"); + buf.append("\n"); + buf.append("public class Lambda1 {\n"); + buf.append(" Comparator<List<?>> c = (l1, l2) -> Integer.compare(l1.size(), l2.size());\n"); + buf.append("}\n"); + ICompilationUnit cu= pack1.createCompilationUnit("Lambda1.java", buf.toString(), false, null); + + AssistContext context= getCorrectionContext(cu, buf.toString().indexOf("->"), 0); + assertNoErrors(context); + List<IJavaCompletionProposal> proposals= collectAssists(context, false); + + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.Comparator;\n"); + buf.append("import java.util.List;\n"); + buf.append("\n"); + buf.append("public class Lambda1 {\n"); + buf.append(" Comparator<List<?>> c = (List<?> l1, List<?> l2) -> Integer.compare(l1.size(), l2.size());\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Add inferred lambda parameter types", proposals); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.Comparator;\n"); + buf.append("import java.util.List;\n"); + buf.append("\n"); + buf.append("public class Lambda1 {\n"); + buf.append(" Comparator<List<?>> c = new Comparator<List<?>>() {\n"); + buf.append(" @Override\n"); + buf.append(" public int compare(List<?> l1, List<?> l2) {\n"); + buf.append(" return Integer.compare(l1.size(), l2.size());\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to anonymous class creation", proposals); + + } + + public void testBug514203_capture1() throws Exception { + Hashtable<String, String> options= JavaCore.getOptions(); + options.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); + JavaCore.setOptions(options); + JavaProjectHelper.addLibrary(fJProject1, new Path(Java18ProjectTestSetup.getJdtAnnotations20Path())); + + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + + StringBuffer buf; + + buf= new StringBuffer(); + buf.append("@org.eclipse.jdt.annotation.NonNullByDefault\n"); + buf.append("package test1;\n"); + pack1.createCompilationUnit("package-info.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public class Lambda2 {\n"); + buf.append(" interface Sink<T> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<? extends Number> source) {\n"); + buf.append(" source.sendTo(a -> a.doubleValue());\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack1.createCompilationUnit("Lambda2.java", buf.toString(), false, null); + + AssistContext context= getCorrectionContext(cu, buf.toString().indexOf("->"), 0); + assertNoErrors(context); + List<IJavaCompletionProposal> proposals= collectAssists(context, false); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public class Lambda2 {\n"); + buf.append(" interface Sink<T> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<? extends Number> source) {\n"); + buf.append(" source.sendTo(Number::doubleValue);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to method reference", proposals); + + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public class Lambda2 {\n"); + buf.append(" interface Sink<T> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<? extends Number> source) {\n"); + buf.append(" source.sendTo((Number a) -> a.doubleValue());\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Add inferred lambda parameter types", proposals); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public class Lambda2 {\n"); + buf.append(" interface Sink<T> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<? extends Number> source) {\n"); + buf.append(" source.sendTo(new Sink<Number>() {\n"); + buf.append(" @Override\n"); + buf.append(" public void receive(Number a) {\n"); + buf.append(" a.doubleValue();\n"); + buf.append(" }\n"); + buf.append(" });\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to anonymous class creation", proposals); + + } + + public void testBug514203_capture2() throws Exception { + Hashtable<String, String> options= JavaCore.getOptions(); + options.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); + JavaCore.setOptions(options); + JavaProjectHelper.addLibrary(fJProject1, new Path(Java18ProjectTestSetup.getJdtAnnotations20Path())); + + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + + StringBuffer buf; + + buf= new StringBuffer(); + buf.append("@org.eclipse.jdt.annotation.NonNullByDefault\n"); + buf.append("package test1;\n"); + pack1.createCompilationUnit("package-info.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.math.BigDecimal;\n"); + buf.append("\n"); + buf.append("public class Lambda3 {\n"); + buf.append(" interface Sink<T extends Number> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends BigDecimal> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo(a -> a.scale());\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack1.createCompilationUnit("Lambda3.java", buf.toString(), false, null); + + AssistContext context= getCorrectionContext(cu, buf.toString().indexOf("->"), 0); + assertNoErrors(context); + List<IJavaCompletionProposal> proposals= collectAssists(context, false); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.math.BigDecimal;\n"); + buf.append("\n"); + buf.append("public class Lambda3 {\n"); + buf.append(" interface Sink<T extends Number> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends BigDecimal> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo(BigDecimal::scale);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to method reference", proposals); + + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.math.BigDecimal;\n"); + buf.append("\n"); + buf.append("public class Lambda3 {\n"); + buf.append(" interface Sink<T extends Number> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends BigDecimal> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo((BigDecimal a) -> a.scale());\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Add inferred lambda parameter types", proposals); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.math.BigDecimal;\n"); + buf.append("\n"); + buf.append("public class Lambda3 {\n"); + buf.append(" interface Sink<T extends Number> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends BigDecimal> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo(new Sink<BigDecimal>() {\n"); + buf.append(" @Override\n"); + buf.append(" public void receive(BigDecimal a) {\n"); + buf.append(" a.scale();\n"); + buf.append(" }\n"); + buf.append(" });\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to anonymous class creation", proposals); + + } + + public void testBug514203_capture3() throws Exception { + Hashtable<String, String> options= JavaCore.getOptions(); + options.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); + JavaCore.setOptions(options); + JavaProjectHelper.addLibrary(fJProject1, new Path(Java18ProjectTestSetup.getJdtAnnotations20Path())); + + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + + StringBuffer buf; + + buf= new StringBuffer(); + buf.append("@org.eclipse.jdt.annotation.NonNullByDefault\n"); + buf.append("package test1;\n"); + pack1.createCompilationUnit("package-info.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.ArrayList;\n"); + buf.append("import java.util.List;\n"); + buf.append("\n"); + buf.append("public class Lambda4 {\n"); + buf.append(" interface Sink<T extends List<Number>> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends ArrayList<Number>> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo(a -> a.size());\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu= pack1.createCompilationUnit("Lambda4.java", buf.toString(), false, null); + + AssistContext context= getCorrectionContext(cu, buf.toString().indexOf("->"), 0); + assertNoErrors(context); + List<IJavaCompletionProposal> proposals= collectAssists(context, false); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.ArrayList;\n"); + buf.append("import java.util.List;\n"); + buf.append("\n"); + buf.append("public class Lambda4 {\n"); + buf.append(" interface Sink<T extends List<Number>> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends ArrayList<Number>> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo(ArrayList<Number>::size);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to method reference", proposals); + + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.ArrayList;\n"); + buf.append("import java.util.List;\n"); + buf.append("\n"); + buf.append("public class Lambda4 {\n"); + buf.append(" interface Sink<T extends List<Number>> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends ArrayList<Number>> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo((ArrayList<Number> a) -> a.size());\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Add inferred lambda parameter types", proposals); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.util.ArrayList;\n"); + buf.append("import java.util.List;\n"); + buf.append("\n"); + buf.append("public class Lambda4 {\n"); + buf.append(" interface Sink<T extends List<Number>> {\n"); + buf.append(" void receive(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" interface Source<U extends ArrayList<Number>> {\n"); + buf.append(" void sendTo(Sink<? super U> c);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" void f(Source<?> source) {\n"); + buf.append(" source.sendTo(new Sink<ArrayList<Number>>() {\n"); + buf.append(" @Override\n"); + buf.append(" public void receive(ArrayList<Number> a) {\n"); + buf.append(" a.size();\n"); + buf.append(" }\n"); + buf.append(" });\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to anonymous class creation", proposals); + + } + + public void testBug514203_lambdaNN() throws Exception { + Hashtable<String, String> options= JavaCore.getOptions(); + options.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); + JavaCore.setOptions(options); + JavaProjectHelper.addLibrary(fJProject1, new Path(Java18ProjectTestSetup.getJdtAnnotations20Path())); + + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + + StringBuffer buf; + + // --- Set up @NonNullByDefault for the package, including ARRAY_CONTENTS -- + + buf= new StringBuffer(); + buf.append("@NonNullByDefault({ PARAMETER, RETURN_TYPE, FIELD, TYPE_BOUND, TYPE_ARGUMENT, ARRAY_CONTENTS })\n"); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import static org.eclipse.jdt.annotation.DefaultLocation.*;\n"); + buf.append("import org.eclipse.jdt.annotation.NonNullByDefault;\n"); + pack1.createCompilationUnit("package-info.java", buf.toString(), false, null); + + // --- Classes that are only referenced -- + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.lang.annotation.ElementType;\n"); + buf.append("import java.lang.annotation.Target;\n"); + buf.append("\n"); + buf.append("@Target(ElementType.TYPE_USE)\n"); + buf.append("@interface X {}\n"); + pack1.createCompilationUnit("X.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.lang.annotation.ElementType;\n"); + buf.append("import java.lang.annotation.Target;\n"); + buf.append("\n"); + buf.append("@Target(ElementType.TYPE_USE)\n"); + buf.append("@interface Y {}\n"); + pack1.createCompilationUnit("Y.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import java.lang.annotation.ElementType;\n"); + buf.append("import java.lang.annotation.Target;\n"); + buf.append("\n"); + buf.append("@Target(ElementType.TYPE_USE)\n"); + buf.append("@interface Z {}\n"); + pack1.createCompilationUnit("Z.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("class Ref<A> {}\n"); + pack1.createCompilationUnit("Ref.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("interface SAM<A> {\n"); + buf.append(" void f(A[] a);\n"); + buf.append("}\n"); + pack1.createCompilationUnit("SAM.java", buf.toString(), false, null); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public class Test {\n"); + buf.append(" static int nn(Object o) {\n"); + buf.append(" return 0;\n"); + buf.append(" }\n"); + buf.append("}\n"); + buf.append(""); + pack1.createCompilationUnit("Test.java", buf.toString(), false, null); + + // --- Classes in which the quick assists are checked (without and with NonNullByDefault in effect at the target location) --- + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN1 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" @NonNullByDefault({})\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = a0 -> Test.nn(a0);\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu1= pack1.createCompilationUnit("LambdaNN1.java", buf.toString(), false, null); + + AssistContext context1= getCorrectionContext(cu1, buf.toString().indexOf("->"), 0); + assertNoErrors(context1); + List<IJavaCompletionProposal> proposals1= collectAssists(context1, false); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN2 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = a0 -> Test.nn(a0);\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + ICompilationUnit cu2= pack1.createCompilationUnit("LambdaNN2.java", buf.toString(), false, null); + + AssistContext context2= getCorrectionContext(cu2, buf.toString().indexOf("->"), 0); + assertNoErrors(context2); + + List<IJavaCompletionProposal> proposals2= collectAssists(context2, false); + + // --- Convert to method reference without and with NNBD --- + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN1 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" @NonNullByDefault({})\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = Test::nn;\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to method reference", proposals1); + + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN2 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = Test::nn;\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to method reference", proposals2); + + // --- Add inferred lambda parameter types without and with NNBD --- + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN1 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" @NonNullByDefault({})\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = (@NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>> @NonNull [] a0) -> Test.nn(a0);\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Add inferred lambda parameter types", proposals1); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN2 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = (Ref<? extends @Y Ref<@X @Nullable String @Y [] @Z []>>[] a0) -> Test.nn(a0);\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Add inferred lambda parameter types", proposals2); + + // --- Convert to anonymous class creation without and with NNBD -- + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN1 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" @NonNullByDefault({})\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = new SAM<@NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>>() {\n"); + buf.append(" @Override\n"); + buf.append(" public void f(\n"); + buf.append(" @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>> @NonNull [] a0) {\n"); + buf.append(" Test.nn(a0);\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to anonymous class creation", proposals1); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("import org.eclipse.jdt.annotation.*;\n"); + buf.append("\n"); + buf.append("public class LambdaNN2 {\n"); + buf.append(" void g(Ref<? extends Ref<@X @Nullable String @Y [] @Z []>>[] data) {\n"); + buf.append(" SAM<? super @NonNull Ref<? extends @NonNull @Y Ref<@X @Nullable String @Y @NonNull [] @Z @NonNull []>>> sam0 = new SAM<Ref<? extends @Y Ref<@X @Nullable String @Y [] @Z []>>>() {\n"); + buf.append(" @Override\n"); + buf.append(" public void f(\n"); + buf.append(" Ref<? extends @Y Ref<@X @Nullable String @Y [] @Z []>>[] a0) {\n"); + buf.append(" Test.nn(a0);\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append(" sam0.f(data);\n"); + buf.append(" }\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to anonymous class creation", proposals2); + } + public void testBug514203_annotatedParametrizedType() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + StringBuffer buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public class Example {\n"); + buf.append(" @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE_USE)\n"); + buf.append(" public @interface X {}\n"); + buf.append("\n"); + buf.append(" interface SAM<T> {\n"); + buf.append(" T f(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" @X\n"); + buf.append(" SAM<String> c = a -> a;\n"); + buf.append("}\n"); + ICompilationUnit cu= pack1.createCompilationUnit("Example.java", buf.toString(), false, null); + + AssistContext context= getCorrectionContext(cu, buf.toString().indexOf("->"), 0); + assertNoErrors(context); + List<IJavaCompletionProposal> proposals= collectAssists(context, false); + + buf= new StringBuffer(); + buf.append("package test1;\n"); + buf.append("\n"); + buf.append("public class Example {\n"); + buf.append(" @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE_USE)\n"); + buf.append(" public @interface X {}\n"); + buf.append("\n"); + buf.append(" interface SAM<T> {\n"); + buf.append(" T f(T t);\n"); + buf.append(" }\n"); + buf.append("\n"); + buf.append(" @X\n"); + buf.append(" SAM<String> c = new @X SAM<String>() {\n"); + buf.append(" @Override\n"); + buf.append(" public String f(String a) {\n"); + buf.append(" return a;\n"); + buf.append(" }\n"); + buf.append(" };\n"); + buf.append("}\n"); + assertProposalPreviewEquals(buf.toString(), "Convert to anonymous class creation", proposals); + } } diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2.java index 2c977a1b91..fe8a80faf0 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2.java @@ -372,10 +372,7 @@ public final class StubUtility2 { decl.setConstructor(false); ITypeBinding bindingReturnType= binding.getReturnType(); - if (bindingReturnType.isWildcardType()) { - ITypeBinding bound= bindingReturnType.getBound(); - bindingReturnType= (bound != null) ? bound : bindingReturnType.getErasure(); - } + bindingReturnType = StubUtility2.replaceWildcardsAndCaptures(bindingReturnType); if (JavaModelUtil.is50OrHigher(javaProject)) { createTypeParameters(imports, context, ast, binding, decl); @@ -498,10 +495,7 @@ public final class StubUtility2 { for (int i= 0; i < params.length; i++) { SingleVariableDeclaration var= ast.newSingleVariableDeclaration(); ITypeBinding type= params[i]; - if (type.isWildcardType()) { - ITypeBinding bound= type.getBound(); - type= (bound != null) ? bound : type.getErasure(); - } + type=replaceWildcardsAndCaptures(type); if (!is50OrHigher) { type= type.getErasure(); var.setType(imports.addImport(type, ast, context, TypeLocation.PARAMETER)); @@ -1008,4 +1002,12 @@ public final class StubUtility2 { } return null; } + + public static ITypeBinding replaceWildcardsAndCaptures(ITypeBinding type) { + while (type.isWildcardType() || type.isCapture() || (type.isArray() && type.getElementType().isCapture())) { + ITypeBinding bound= type.getBound(); + type= (bound != null) ? bound : type.getErasure(); + } + return type; + } } diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodeFactory.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodeFactory.java index fba38d778e..1ff93e8426 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodeFactory.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodeFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2017 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -17,6 +17,7 @@ import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotatableType; import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Dimension; @@ -43,7 +44,9 @@ import org.eclipse.jdt.core.dom.VariableDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; +import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation; +import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2; import org.eclipse.jdt.internal.corext.util.JDTUIHelperClasses; /** @@ -354,36 +357,29 @@ public class ASTNodeFactory { return result; } + /** + * Create a Type suitable as the creationType in a ClassInstanceCreation expression. + * @param ast The AST to create the nodes for. + * @param typeBinding binding representing the given class type + * @param importRewrite the import rewrite to use + * @param importContext the import context used to determine which (null) annotations to consider + * @return a Type suitable as the creationType in a ClassInstanceCreation expression. + */ public static Type newCreationType(AST ast, ITypeBinding typeBinding, ImportRewrite importRewrite, ImportRewriteContext importContext) { if (typeBinding.isParameterizedType()) { Type baseType= newCreationType(ast, typeBinding.getTypeDeclaration(), importRewrite, importContext); + IAnnotationBinding[] typeAnnotations= importContext.removeRedundantTypeAnnotations(typeBinding.getTypeAnnotations(), TypeLocation.NEW, typeBinding); + for (IAnnotationBinding typeAnnotation : typeAnnotations) { + ((AnnotatableType)baseType).annotations().add(importRewrite.addAnnotation(typeAnnotation, ast, importContext)); + } ParameterizedType parameterizedType= ast.newParameterizedType(baseType); for (ITypeBinding typeArgument : typeBinding.getTypeArguments()) { - parameterizedType.typeArguments().add(newCreationType(ast, typeArgument, importRewrite, importContext)); + typeArgument= StubUtility2.replaceWildcardsAndCaptures(typeArgument); + parameterizedType.typeArguments().add(importRewrite.addImport(typeArgument, ast, importContext, TypeLocation.TYPE_ARGUMENT)); } return parameterizedType; - - } else if (typeBinding.isParameterizedType()) { - Type elementType= newCreationType(ast, typeBinding.getElementType(), importRewrite, importContext); - ArrayType arrayType= ast.newArrayType(elementType, 0); - while (typeBinding.isArray()) { - Dimension dimension= ast.newDimension(); - IAnnotationBinding[] typeAnnotations= typeBinding.getTypeAnnotations(); - for (IAnnotationBinding typeAnnotation : typeAnnotations) { - dimension.annotations().add(importRewrite.addAnnotation(typeAnnotation, ast, importContext)); - } - arrayType.dimensions().add(dimension); - typeBinding= typeBinding.getComponentType(); - } - return arrayType; - - } else if (typeBinding.isWildcardType()) { - ITypeBinding bound= typeBinding.getBound(); - typeBinding= (bound != null) ? bound : typeBinding.getErasure(); - return newCreationType(ast, typeBinding, importRewrite, importContext); - } else { - return importRewrite.addImport(typeBinding, ast, importContext); + return importRewrite.addImport(typeBinding, ast, importContext, TypeLocation.NEW); } } } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java index e61cab06b1..78faa0705e 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java @@ -130,6 +130,7 @@ import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving; import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; +import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2; import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.Bindings; @@ -1225,7 +1226,9 @@ public class QuickAssistProcessor implements IQuickAssistProcessor { typeMethodReference.setName((SimpleName) rewrite.createCopyTarget(methodInvocation.getName())); importRewrite= StubUtility.createImportRewrite(context.getASTRoot(), true); ITypeBinding invocationTypeBinding= ASTNodes.getInvocationType(methodInvocation, methodBinding, invocationQualifier); - typeMethodReference.setType(importRewrite.addImport(invocationTypeBinding, ast)); + invocationTypeBinding=StubUtility2.replaceWildcardsAndCaptures(invocationTypeBinding); + ImportRewriteContext importRewriteContext=new ContextSensitiveImportRewriteContext(lambda, importRewrite); + typeMethodReference.setType(importRewrite.addImport(invocationTypeBinding, ast, importRewriteContext, TypeLocation.OTHER)); typeMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodInvocation.typeArguments())); } else { @@ -1384,13 +1387,14 @@ public class QuickAssistProcessor implements IQuickAssistProcessor { ImportRewrite importRewrite= StubUtility.createImportRewrite(context.getASTRoot(), true); rewrite.set(lambda, LambdaExpression.PARENTHESES_PROPERTY, Boolean.valueOf(true), null); - + ContextSensitiveImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(lambda, importRewrite); ITypeBinding[] parameterTypes= methodBinding.getParameterTypes(); for (int i= 0; i < noOfLambdaParams; i++) { VariableDeclaration param= lambdaParameters.get(i); SingleVariableDeclaration newParam= ast.newSingleVariableDeclaration(); newParam.setName(ast.newSimpleName(param.getName().getIdentifier())); - newParam.setType(importRewrite.addImport(parameterTypes[i], ast)); + ITypeBinding type= StubUtility2.replaceWildcardsAndCaptures(parameterTypes[i]); + newParam.setType(importRewrite.addImport(type, ast, importRewriteContext, TypeLocation.PARAMETER)); rewrite.replace(param, newParam, null); } |
