Bug 514203 - [quick assist] Lambda: improve handling of wildcards &
captures and avoid creating redundant @NonNull
Change-Id: I70a371ffa5fa2180b60a9bc976d7d859422b842b
Signed-off-by: Till Brychcy <register.eclipse@brychcy.de>
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 dfa33cf..154d8cd 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 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 @@
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 2c977a1..fe8a80f 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 @@
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 @@
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 @@
}
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 fba38d7..1ff93e8 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.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.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 @@
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 e61cab0..78faa07 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.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 @@
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 @@
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);
}