Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2016-10-17 21:38:07 +0000
committerStephan Herrmann2017-03-05 23:44:58 +0000
commite7d6d8a91612da3f3cae0b22ddd55df43d4ee554 (patch)
tree75fa42a06ccdd59ca88e3b7bfe410adfbd8ef80b
parentd111a821fb2982dae427d067dc0f6a0a36b9c804 (diff)
downloadeclipse.jdt.core-e7d6d8a91612da3f3cae0b22ddd55df43d4ee554.tar.gz
eclipse.jdt.core-e7d6d8a91612da3f3cae0b22ddd55df43d4ee554.tar.xz
eclipse.jdt.core-e7d6d8a91612da3f3cae0b22ddd55df43d4ee554.zip
Bug 410218 - Optional warning for arguments of "unexpected" types toI20170305-2000
Map#get(Object), Collection#remove(Object) et al. Also-By: Till Brychcy <register.eclipse@brychcy.de> Change-Id: I171086d745e1ba15f64cf66264ac35c1a07ef437
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java51
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java4
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java520
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java6
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java7
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java26
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java28
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java186
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java44
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java15
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java17
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java75
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java17
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java28
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties7
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java58
17 files changed, 1076 insertions, 16 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
index f5e7ec224b..ea86675dfc 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
@@ -872,6 +872,9 @@ public void test012b(){
" unavoidableGenericProblems + ignore unavoidable type safety problems\n" +
" due to raw APIs\n" +
" unchecked + unchecked type operation\n" +
+ " unlikelyCollectionMethodArgumentType unlikely argument type for collection\n" +
+ " methods using Object\n" +
+ " unlikelyEqualsArgumentType unlikely argument type for equals()\n" +
" unnecessaryElse unnecessary else clause\n" +
" unqualifiedField unqualified reference to field\n" +
" unused macro for unusedAllocation, unusedArgument,\n" +
@@ -1066,6 +1069,9 @@ public void test012b(){
" <option key=\"org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock\" value=\"ignore\"/>\n" +
" <option key=\"org.eclipse.jdt.core.compiler.problem.unhandledWarningToken\" value=\"warning\"/>\n" +
" <option key=\"org.eclipse.jdt.core.compiler.problem.uninternedIdentityComparison\" value=\"disabled\"/>\n" +
+ " <option key=\"org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType\" value=\"warning\"/>\n" +
+ " <option key=\"org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict\" value=\"disabled\"/>\n" +
+ " <option key=\"org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType\" value=\"info\"/>\n" +
" <option key=\"org.eclipse.jdt.core.compiler.problem.unnecessaryElse\" value=\"ignore\"/>\n" +
" <option key=\"org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck\" value=\"ignore\"/>\n" +
" <option key=\"org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess\" value=\"ignore\"/>\n" +
@@ -1971,7 +1977,6 @@ public void test032(){
" public void foo5(final Map<XX<?, ?>, XY> p1) {\n" +
" p1.putAll(m1);\n" +
" }\n" +
- "\n" +
" public void foo6(final Map<XX<?, ?>, XY> p1) {\n" +
" m1.keySet().retainAll(p1.keySet());\n" +
" m2.keySet().retainAll(p1.keySet());\n" +
@@ -2152,7 +2157,6 @@ public void test032(){
" public void foo5(final Map<XX<?, ?>, XY> p1) {\n" +
" p1.putAll(m1);\n" +
" }\n" +
- "\n" +
" public void foo6(final Map<XX<?, ?>, XY> p1) {\n" +
" m1.keySet().retainAll(p1.keySet());\n" +
" m2.keySet().retainAll(p1.keySet());\n" +
@@ -12120,6 +12124,49 @@ public void test329_nowarn_options() {
true);
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=408815
+// -warn option - regression tests to check option unlikelyCollectionMethodArgumentType
+public void test330_warn_options() {
+ this.runConformTest(
+ new String[] {
+ "p/X.java",
+ "package p;\n" +
+ "import java.util.Map;\n" +
+ "public class X {\n" +
+ " Integer foo(Map<String,Integer> map) {\n" +
+ " return map.get(3);\n" +
+ " }\n" +
+ "}\n",
+ },
+ "\"" + OUTPUT_DIR + File.separator + "p" + File.separator + "X.java\""
+ + " -sourcepath \"" + OUTPUT_DIR + "\""
+ + " -1.5"
+ + " -warn:-unlikelyCollectionMethodArgumentType -proc:none -d \"" + OUTPUT_DIR + "\"",
+ "",
+ "",
+ true);
+}//https://bugs.eclipse.org/bugs/show_bug.cgi?id=408815
+//-warn option - regression tests to check option unlikelyEqualsArgumentType
+public void test331_warn_options() {
+ this.runConformTest(
+ new String[] {
+ "p/X.java",
+ "package p;\n" +
+ "public class X {\n" +
+ " boolean foo() {\n" +
+ " return \"three\".equals(3);\n" +
+ " }\n" +
+ "}\n",
+ },
+ "\"" + OUTPUT_DIR + File.separator + "p" + File.separator + "X.java\""
+ + " -sourcepath \"" + OUTPUT_DIR + "\""
+ + " -1.5"
+ + " -info:-unlikelyEqualsArgumentType -proc:none -d \"" + OUTPUT_DIR + "\"",
+ "",
+ "",
+ true);
+}
+
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=375409
public void testBug375409a() {
this.runConformTest(
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index 1d93cb4e52..fad307ec04 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -1046,6 +1046,8 @@ public void test011_problem_categories() {
expectedProblemAttributes.put("UninitializedNonNullField", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("UninitializedNonNullFieldHintMissingDefault", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("UninternedIdentityComparison", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
+ expectedProblemAttributes.put("UnlikelyCollectionMethodArgumentType", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("UnlikelyEqualsArgumentType", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("UnmatchedBracket", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
expectedProblemAttributes.put("UnnecessaryArgumentCast", DEPRECATED);
expectedProblemAttributes.put("UnnecessaryCast", new ProblemAttributes(CategorizedProblem.CAT_UNNECESSARY_CODE));
@@ -1887,6 +1889,8 @@ public void test012_compiler_problems_tuning() {
expectedProblemAttributes.put("UninitializedNonNullField", SKIP);
expectedProblemAttributes.put("UninitializedNonNullFieldHintMissingDefault", SKIP);
expectedProblemAttributes.put("UninternedIdentityComparison", SKIP);
+ expectedProblemAttributes.put("UnlikelyCollectionMethodArgumentType", new ProblemAttributes(JavaCore.COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE));
+ expectedProblemAttributes.put("UnlikelyEqualsArgumentType", new ProblemAttributes(JavaCore.COMPILER_PB_UNLIKELY_EQUALS_ARGUMENT_TYPE));
expectedProblemAttributes.put("UnmatchedBracket", SKIP);
expectedProblemAttributes.put("UnnecessaryArgumentCast", SKIP);
expectedProblemAttributes.put("UnnecessaryCast", new ProblemAttributes(JavaCore.COMPILER_PB_UNNECESSARY_TYPE_CHECK));
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java
index b97333cc1a..46de7276d4 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2001, 2014 IBM Corporation and others.
+ * Copyright (c) 2001, 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
@@ -10,6 +10,7 @@
* Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
* bug 185682 - Increment/decrement operators mark local variables as read
* bug 328281 - visibility leaks not detected when analyzing unused field in private class
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -2703,4 +2704,521 @@ public void test0063() throws Exception {
true/*shouldFlushOutputDirectory*/,
customOptions);
}
+// Collection: contains & remove & get
+public void testBug410218a() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5)
+ return;
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "class X {\n" +
+ " void test() {\n" +
+ " Set<Short> set = new HashSet<Short>();\n" +
+ " short one = 1;\n" +
+ " set.add(one);\n" +
+ "\n" +
+ " if (set.contains(\"ONE\")) // bad\n" +
+ " set.remove(\"ONE\"); // bad\n" +
+ " if (set.contains(1)) // bad\n" +
+ " set.remove(1); // bad (tries to remove \"Integer 1\")\n" +
+ " System.out.println(set); // shows that the \"Short 1\" is still in!\n" +
+ "\n" +
+ " if (set.contains(one)) // ok\n" +
+ " set.remove(one); // ok\n" +
+ " if (set.contains(Short.valueOf(one))) // ok\n" +
+ " set.remove(Short.valueOf(one)); // ok\n" +
+ " System.out.println(set);\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in X.java (at line 8)\n" +
+ " if (set.contains(\"ONE\")) // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for contains(Object) on a Collection<Short>\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 9)\n" +
+ " set.remove(\"ONE\"); // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for remove(Object) on a Collection<Short>\n" +
+ "----------\n" +
+ "3. WARNING in X.java (at line 10)\n" +
+ " if (set.contains(1)) // bad\n" +
+ " ^\n" +
+ "Unlikely argument type int for contains(Object) on a Collection<Short>\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 11)\n" +
+ " set.remove(1); // bad (tries to remove \"Integer 1\")\n" +
+ " ^\n" +
+ "Unlikely argument type int for remove(Object) on a Collection<Short>\n" +
+ "----------\n");
+}
+// HashSet vs. TreeSet
+public void testBug410218b() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5)
+ return;
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "class X {\n" +
+ " <T> void test(Set<HashSet<T>> hss, TreeSet<T> ts, LinkedHashSet<T> lhs) {\n" +
+ " if (hss.contains(ts)) // bad\n" +
+ " hss.remove(ts); // bad\n" +
+ " if (hss.contains((Set<T>)ts)) // ok\n" +
+ " hss.remove((Set<T>)ts); // ok\n" +
+ " if (hss.contains(lhs)) // ok\n" +
+ " hss.remove(lhs); // ok\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in X.java (at line 4)\n" +
+ " if (hss.contains(ts)) // bad\n" +
+ " ^^\n" +
+ "Unlikely argument type TreeSet<T> for contains(Object) on a Collection<HashSet<T>>\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 5)\n" +
+ " hss.remove(ts); // bad\n" +
+ " ^^\n" +
+ "Unlikely argument type TreeSet<T> for remove(Object) on a Collection<HashSet<T>>\n" +
+ "----------\n");
+}
+// HashSet vs. TreeSet or: strict
+public void testBug410218b2() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE_STRICT, JavaCore.ENABLED);
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "class X {\n" +
+ " <T> void test(Set<HashSet<T>> hss, TreeSet<T> ts, LinkedHashSet<T> lhs) {\n" +
+ " if (hss.contains(ts)) // bad\n" +
+ " hss.remove(ts); // bad\n" +
+ " if (hss.contains((Set<T>)ts)) // bad (because of strict check)\n" +
+ " hss.remove((Set<T>)ts); // bad (because of strict check)\n" +
+ " if (hss.contains(lhs)) // ok\n" +
+ " hss.remove(lhs); // ok\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in X.java (at line 4)\n" +
+ " if (hss.contains(ts)) // bad\n" +
+ " ^^\n" +
+ "Unlikely argument type TreeSet<T> for contains(Object) on a Collection<HashSet<T>>\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 5)\n" +
+ " hss.remove(ts); // bad\n" +
+ " ^^\n" +
+ "Unlikely argument type TreeSet<T> for remove(Object) on a Collection<HashSet<T>>\n" +
+ "----------\n" +
+ "3. WARNING in X.java (at line 6)\n" +
+ " if (hss.contains((Set<T>)ts)) // bad (because of strict check)\n" +
+ " ^^^^^^^^^^\n" +
+ "Unlikely argument type Set<T> for contains(Object) on a Collection<HashSet<T>>\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 7)\n" +
+ " hss.remove((Set<T>)ts); // bad (because of strict check)\n" +
+ " ^^^^^^^^^^\n" +
+ "Unlikely argument type Set<T> for remove(Object) on a Collection<HashSet<T>>\n" +
+ "----------\n",
+ null/*classLibraries*/,
+ true/*shouldFlushOutputDirectory*/,
+ customOptions);
+}
+// Map: contains* & remove & get
+public void testBug410218c() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5)
+ return;
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "class X {\n" +
+ " Number test(Map<? extends Number, Number> m, boolean f) {\n" +
+ " if (m.containsKey(\"ONE\")) // bad\n" +
+ " m.remove(\"ONE\"); // bad\n" +
+ " if (m.containsValue(\"ONE\")) // bad\n" +
+ " m.remove(\"ONE\"); // bad\n" +
+ " short one = 1;\n" +
+ " if (m.containsKey(one)) // almost ok\n" +
+ " m.remove(one); // almost ok\n" +
+ " if (m.containsValue(Short.valueOf(one))) // ok\n" +
+ " m.remove(Short.valueOf(one)); // almost ok\n" +
+ " if (f)\n" +
+ " return m.get(\"ONE\"); // bad\n" +
+ " return m.get(one);\n // almost ok\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in X.java (at line 4)\n" +
+ " if (m.containsKey(\"ONE\")) // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for containsKey(Object) on a Map<capture#1-of ? extends Number,Number>\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 5)\n" +
+ " m.remove(\"ONE\"); // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for remove(Object) on a Map<capture#2-of ? extends Number,Number>\n" +
+ "----------\n" +
+ "3. WARNING in X.java (at line 6)\n" +
+ " if (m.containsValue(\"ONE\")) // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for containsValue(Object) on a Map<capture#3-of ? extends Number,Number>\n" +
+ "----------\n" +
+ "4. WARNING in X.java (at line 7)\n" +
+ " m.remove(\"ONE\"); // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for remove(Object) on a Map<capture#4-of ? extends Number,Number>\n" +
+ "----------\n" +
+ "5. WARNING in X.java (at line 14)\n" +
+ " return m.get(\"ONE\"); // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for get(Object) on a Map<capture#9-of ? extends Number,Number>\n" +
+ "----------\n");
+}
+// Collection: {contains,remove,retain}All, non-generic sub type of Collection, configured to be ERROR
+public void testBug410218d() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE, JavaCore.ERROR);
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "interface NumberCollection extends Collection<Number> {}\n" +
+ "class X {\n" +
+ " void test(NumberCollection numbers, List<Integer> ints, Set<String> stringSet) {\n" +
+ " if (numbers.containsAll(ints)) // ok\n" +
+ " numbers.removeAll(ints); // ok\n" +
+ " else\n" +
+ " numbers.retainAll(ints); // ok\n" +
+ "\n" +
+ " numbers.removeAll(stringSet); // bad\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 10)\n" +
+ " numbers.removeAll(stringSet); // bad\n" +
+ " ^^^^^^^^^\n" +
+ "Unlikely argument type Set<String> for removeAll(Collection<?>) on a Collection<Number>\n" +
+ "----------\n",
+ null/*classLibraries*/,
+ true/*shouldFlushOutputDirectory*/,
+ customOptions);
+}
+// List.indexOf: w/ and w/o @SuppressWarnings
+public void testBug410218e() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_5)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE, JavaCore.WARNING);
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ "import java.util.*;\n" +
+ "class X {\n" +
+ " int test1(List<Integer> ints, Object o) {\n" +
+ " return ints.indexOf(\"ONE\"); // bad\n" +
+ " }\n" +
+ " @SuppressWarnings(\"unlikely-arg-type\")\n" +
+ " int test2(List<Integer> ints, boolean f, Object o) {\n" +
+ " if (f)\n" +
+ " return ints.indexOf(\"ONE\"); // bad but suppressed\n" +
+ " return ints.indexOf(o); // supertype\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in X.java (at line 4)\n" +
+ " return ints.indexOf(\"ONE\"); // bad\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type String for indexOf(Object) on a List<Integer>\n" +
+ "----------\n",
+ null/*classLibraries*/,
+ true/*shouldFlushOutputDirectory*/,
+ customOptions);
+}
+
+// Method references, equals, wildcards
+public void testBug410218f() {
+ if (this.complianceLevel < ClassFileConstants.JDK1_8)
+ return;
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE, JavaCore.WARNING);
+ customOptions.put(JavaCore.COMPILER_PB_UNLIKELY_EQUALS_ARGUMENT_TYPE, JavaCore.INFO);
+ runNegativeTest(
+ new String[] {
+ "test/TestUnlikely.java",
+ "package test;\n" +
+ "\n" +
+ "import java.util.Collection;\n" +
+ "import java.util.Iterator;\n" +
+ "import java.util.List;\n" +
+ "import java.util.Map;\n" +
+ "import java.util.Objects;\n" +
+ "import java.util.Set;\n" +
+ "import java.util.function.BiPredicate;\n" +
+ "import java.util.function.Predicate;\n" +
+ "\n" +
+ "public class TestUnlikely {\n" +
+ " interface Interface {\n" +
+ " }\n" +
+ "\n" +
+ " interface OtherInterface {\n" +
+ " }\n" +
+ "\n" +
+ " static class NonFinal implements Interface {\n" +
+ " }\n" +
+ "\n" +
+ " static class Sub extends NonFinal implements OtherInterface {\n" +
+ " }\n" +
+ "\n" +
+ " static final class Final implements Interface {\n" +
+ " }\n" +
+ "\n" +
+ " void f1(List<Interface> c, Interface i, OtherInterface o, Final f, NonFinal nf, Sub s) {\n" +
+ " c.remove(i);\n" +
+ " c.remove(o); // warning: unrelated interface\n" +
+ " c.remove(f);\n" +
+ " c.remove(nf);\n" +
+ " c.remove(s);\n" +
+ " }\n" +
+ "\n" +
+ " void f2(List<OtherInterface> c, Interface i, OtherInterface o, Final f, NonFinal nf, Sub s) {\n" +
+ " c.remove(i); // warning: unrelated interface\n" +
+ " c.remove(o);\n" +
+ " c.remove(f); // warning: impossible\n" +
+ " c.remove(nf); // warning: castable, but not supertype\n" +
+ " c.remove(s);\n" +
+ " }\n" +
+ "\n" +
+ " void f3(List<Final> c, Interface i, OtherInterface o, Final f, NonFinal nf, Sub s) {\n" +
+ " c.remove(i); // supertype\n" +
+ " c.remove(o); // warning: impossible\n" +
+ " c.remove(f);\n" +
+ " c.remove(nf); // warning: impossible\n" +
+ " c.remove(s); // warning: impossible\n" +
+ " }\n" +
+ "\n" +
+ " void f4(List<NonFinal> c, Interface i, OtherInterface o, Final f, NonFinal nf, Sub s) {\n" +
+ " c.remove(i); // supertype\n" +
+ " c.remove(o); // warning: unrelated interface\n" +
+ " c.remove(f); // warning: impossible\n" +
+ " c.remove(nf);\n" +
+ " c.remove(s);\n" +
+ " }\n" +
+ "\n" +
+ " void f5(List<Sub> c, Interface i, OtherInterface o, Final f, NonFinal nf, Sub s) {\n" +
+ " c.remove(i); // supertype\n" +
+ " c.remove(o); // supertype\n" +
+ " c.remove(f); // warning: impossible\n" +
+ " c.remove(nf); // supertype\n" +
+ " c.remove(s);\n" +
+ " }\n" +
+ "\n" +
+ " <K, V> void map(Map<K, V> map, K key, V value) {\n" +
+ " map.containsKey(key);\n" +
+ " map.containsKey(value); // warning\n" +
+ " map.containsValue(key); // warning\n" +
+ " map.containsValue(value);\n" +
+ " }\n" +
+ "\n" +
+ " boolean wildcards(Collection<?> c, Iterable<?> s) {\n" +
+ " for (Iterator<?> iterator = s.iterator(); iterator.hasNext();) {\n" +
+ " if (c.contains(iterator.next())) {\n" +
+ " return true;\n" +
+ " }\n" +
+ " }\n" +
+ " return false;\n" +
+ " }\n" +
+ "\n" +
+ " <T, U extends T> boolean relatedTypeVariables(Collection<T> c, Iterable<U> s) {\n" +
+ " for (Iterator<?> iterator = s.iterator(); iterator.hasNext();) {\n" +
+ " if (c.contains(iterator.next())) {\n" +
+ " return true;\n" +
+ " }\n" +
+ " }\n" +
+ " return false;\n" +
+ " }\n" +
+ "\n" +
+ " <T, U> boolean unrelatedTypeVariables(Collection<T> c, Iterable<U> s) {\n" +
+ " for (Iterator<U> iterator = s.iterator(); iterator.hasNext();) {\n" +
+ " if (c.contains(iterator.next())) { // warning\n" +
+ " return true;\n" +
+ " }\n" +
+ " }\n" +
+ " return false;\n" +
+ " }\n" +
+ "\n" +
+ " void all(List<NonFinal> c, Collection<Sub> s, Set<Final> other) {\n" +
+ " c.removeAll(s);\n" +
+ " s.removeAll(c);\n" +
+ " c.removeAll(other); // warning\n" +
+ " }\n" +
+ "\n" +
+ " void methodRef(Set<Interface> c, Interface i, OtherInterface o, Final f, NonFinal nf, Sub s) {\n" +
+ " Predicate<Interface> p1 = c::contains;\n" +
+ " BiPredicate<Collection<Interface>, Interface> bp1 = Collection<Interface>::contains;\n" +
+ " Predicate<OtherInterface> p2 = c::contains; // warning\n" +
+ " BiPredicate<Collection<Interface>, OtherInterface> bp2 = Collection<Interface>::contains; // warning\n" +
+ " p1.test(i);\n" +
+ " bp1.test(c, i);\n" +
+ " p2.test(o);\n" +
+ " bp2.test(c, o);\n" +
+ " }\n" +
+ "\n" +
+ " void equals(String s, Integer i, Number n) {\n" +
+ " s.equals(i); // info\n" +
+ " i.equals(s); // info\n" +
+ " i.equals(n);\n" +
+ " n.equals(i);\n" +
+ "\n" +
+ " Predicate<String> p1 = i::equals; // info\n" +
+ " p1.test(s);\n" +
+ "\n" +
+ " BiPredicate<String, Integer> bp2 = Object::equals; // info\n" +
+ " bp2.test(s, i);\n" +
+ "\n" +
+ " Objects.equals(s, i); // info\n" +
+ " Objects.equals(i, s); // info\n" +
+ " Objects.equals(n, i);\n" +
+ " Objects.equals(i, n);\n" +
+ "\n" +
+ " BiPredicate<String, Integer> bp3 = Objects::equals; // info\n" +
+ " bp3.test(s, i);\n" +
+ " }\n" +
+ "\n" +
+ "}\n" +
+ "",
+ },
+ "----------\n" +
+ "1. WARNING in test\\TestUnlikely.java (at line 30)\n" +
+ " c.remove(o); // warning: unrelated interface\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.OtherInterface for remove(Object) on a Collection<TestUnlikely.Interface>\n" +
+ "----------\n" +
+ "2. WARNING in test\\TestUnlikely.java (at line 37)\n" +
+ " c.remove(i); // warning: unrelated interface\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.Interface for remove(Object) on a Collection<TestUnlikely.OtherInterface>\n" +
+ "----------\n" +
+ "3. WARNING in test\\TestUnlikely.java (at line 39)\n" +
+ " c.remove(f); // warning: impossible\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.Final for remove(Object) on a Collection<TestUnlikely.OtherInterface>\n" +
+ "----------\n" +
+ "4. WARNING in test\\TestUnlikely.java (at line 40)\n" +
+ " c.remove(nf); // warning: castable, but not supertype\n" +
+ " ^^\n" +
+ "Unlikely argument type TestUnlikely.NonFinal for remove(Object) on a Collection<TestUnlikely.OtherInterface>\n" +
+ "----------\n" +
+ "5. WARNING in test\\TestUnlikely.java (at line 46)\n" +
+ " c.remove(o); // warning: impossible\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.OtherInterface for remove(Object) on a Collection<TestUnlikely.Final>\n" +
+ "----------\n" +
+ "6. WARNING in test\\TestUnlikely.java (at line 48)\n" +
+ " c.remove(nf); // warning: impossible\n" +
+ " ^^\n" +
+ "Unlikely argument type TestUnlikely.NonFinal for remove(Object) on a Collection<TestUnlikely.Final>\n" +
+ "----------\n" +
+ "7. WARNING in test\\TestUnlikely.java (at line 49)\n" +
+ " c.remove(s); // warning: impossible\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.Sub for remove(Object) on a Collection<TestUnlikely.Final>\n" +
+ "----------\n" +
+ "8. WARNING in test\\TestUnlikely.java (at line 54)\n" +
+ " c.remove(o); // warning: unrelated interface\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.OtherInterface for remove(Object) on a Collection<TestUnlikely.NonFinal>\n" +
+ "----------\n" +
+ "9. WARNING in test\\TestUnlikely.java (at line 55)\n" +
+ " c.remove(f); // warning: impossible\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.Final for remove(Object) on a Collection<TestUnlikely.NonFinal>\n" +
+ "----------\n" +
+ "10. WARNING in test\\TestUnlikely.java (at line 63)\n" +
+ " c.remove(f); // warning: impossible\n" +
+ " ^\n" +
+ "Unlikely argument type TestUnlikely.Final for remove(Object) on a Collection<TestUnlikely.Sub>\n" +
+ "----------\n" +
+ "11. WARNING in test\\TestUnlikely.java (at line 70)\n" +
+ " map.containsKey(value); // warning\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type V for containsKey(Object) on a Map<K,V>\n" +
+ "----------\n" +
+ "12. WARNING in test\\TestUnlikely.java (at line 71)\n" +
+ " map.containsValue(key); // warning\n" +
+ " ^^^\n" +
+ "Unlikely argument type K for containsValue(Object) on a Map<K,V>\n" +
+ "----------\n" +
+ "13. WARNING in test\\TestUnlikely.java (at line 95)\n" +
+ " if (c.contains(iterator.next())) { // warning\n" +
+ " ^^^^^^^^^^^^^^^\n" +
+ "Unlikely argument type U for contains(Object) on a Collection<T>\n" +
+ "----------\n" +
+ "14. WARNING in test\\TestUnlikely.java (at line 105)\n" +
+ " c.removeAll(other); // warning\n" +
+ " ^^^^^\n" +
+ "Unlikely argument type Set<TestUnlikely.Final> for removeAll(Collection<?>) on a Collection<TestUnlikely.NonFinal>\n" +
+ "----------\n" +
+ "15. WARNING in test\\TestUnlikely.java (at line 111)\n" +
+ " Predicate<OtherInterface> p2 = c::contains; // warning\n" +
+ " ^^^^^^^^^^^\n" +
+ "Unlikely argument type TestUnlikely.OtherInterface for contains(Object) on a Collection<TestUnlikely.Interface>\n" +
+ "----------\n" +
+ "16. WARNING in test\\TestUnlikely.java (at line 112)\n" +
+ " BiPredicate<Collection<Interface>, OtherInterface> bp2 = Collection<Interface>::contains; // warning\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Unlikely argument type TestUnlikely.OtherInterface for contains(Object) on a Collection<TestUnlikely.Interface>\n" +
+ "----------\n" +
+ "17. INFO in test\\TestUnlikely.java (at line 120)\n" +
+ " s.equals(i); // info\n" +
+ " ^\n" +
+ "Unlikely argument type for equals(): Integer seems to be unrelated to String\n" +
+ "----------\n" +
+ "18. INFO in test\\TestUnlikely.java (at line 121)\n" +
+ " i.equals(s); // info\n" +
+ " ^\n" +
+ "Unlikely argument type for equals(): String seems to be unrelated to Integer\n" +
+ "----------\n" +
+ "19. INFO in test\\TestUnlikely.java (at line 125)\n" +
+ " Predicate<String> p1 = i::equals; // info\n" +
+ " ^^^^^^^^^\n" +
+ "Unlikely argument type for equals(): String seems to be unrelated to Integer\n" +
+ "----------\n" +
+ "20. INFO in test\\TestUnlikely.java (at line 128)\n" +
+ " BiPredicate<String, Integer> bp2 = Object::equals; // info\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Unlikely argument type for equals(): Integer seems to be unrelated to String\n" +
+ "----------\n" +
+ "21. INFO in test\\TestUnlikely.java (at line 131)\n" +
+ " Objects.equals(s, i); // info\n" +
+ " ^\n" +
+ "Unlikely argument type for equals(): Integer seems to be unrelated to String\n" +
+ "----------\n" +
+ "22. INFO in test\\TestUnlikely.java (at line 132)\n" +
+ " Objects.equals(i, s); // info\n" +
+ " ^\n" +
+ "Unlikely argument type for equals(): String seems to be unrelated to Integer\n" +
+ "----------\n" +
+ "23. INFO in test\\TestUnlikely.java (at line 136)\n" +
+ " BiPredicate<String, Integer> bp3 = Objects::equals; // info\n" +
+ " ^^^^^^^^^^^^^^^\n" +
+ "Unlikely argument type for equals(): Integer seems to be unrelated to String\n" +
+ "----------\n"
+ ,
+ null/*classLibraries*/,
+ true/*shouldFlushOutputDirectory*/,
+ customOptions);
+}
} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index f95d7c8c78..0f4bb64958 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -4012,6 +4012,12 @@ private void handleErrorOrWarningToken(String token, boolean isEnabling, int sev
} else if (token.equals("unchecked") || token.equals("unsafe")) {//$NON-NLS-1$ //$NON-NLS-2$
setSeverity(CompilerOptions.OPTION_ReportUncheckedTypeOperation, severity, isEnabling);
return;
+ } else if (token.equals("unlikelyCollectionMethodArgumentType")) { //$NON-NLS-1$
+ setSeverity(CompilerOptions.OPTION_ReportUnlikelyCollectionMethodArgumentType, severity, isEnabling);
+ return;
+ } else if (token.equals("unlikelyEqualsArgumentType")) { //$NON-NLS-1$
+ setSeverity(CompilerOptions.OPTION_ReportUnlikelyEqualsArgumentType, severity, isEnabling);
+ return;
} else if (token.equals("unnecessaryElse")) {//$NON-NLS-1$
setSeverity(CompilerOptions.OPTION_ReportUnnecessaryElse, severity, isEnabling);
return;
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
index c56494df66..5f2f54f9b7 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
@@ -412,6 +412,9 @@ misc.usage.warn = {1} {2}\n\
\ unavoidableGenericProblems + ignore unavoidable type safety problems\n\
\ due to raw APIs\n\
\ unchecked + unchecked type operation\n\
+\ unlikelyCollectionMethodArgumentType unlikely argument type for collection\n\
+\ methods using 'Object'\n\
+\ unlikelyEqualsArgumentType unlikely argument type for equals()\n\
\ unnecessaryElse unnecessary else clause\n\
\ unqualifiedField unqualified reference to field\n\
\ unused macro for unusedAllocation, unusedArgument,\n\
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index c0ac572225..12f6fe05e1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -196,6 +196,8 @@
* IllegalParameterNullityRedefinition
* ContradictoryNullAnnotationsInferredFunctionType
* IllegalReturnNullityRedefinitionFreeTypeVariable
+ * UnlikelyCollectionMethodArgumentType
+ * UnlikelyEqualsArgumentType
* Jesper S Moller - added the following constants
* TargetTypeNotAFunctionalInterface
* OuterLocalMustBeEffectivelyFinal
@@ -1889,4 +1891,9 @@ void setSourceStart(int sourceStart);
int LambdaShapeComputationError = 1101;
/** @since 3.13 */
int ProblemNotAnalysed = 1102;
+
+ /** @since 3.13 */
+ int UnlikelyCollectionMethodArgumentType = 1200;
+ /** @since 3.13 */
+ int UnlikelyEqualsArgumentType = 1201;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index 44c2ad0fad..a1be3fddef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -53,6 +53,7 @@
* Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
* Bug 472618 - [compiler][null] assertNotNull vs. Assert.assertNotNull
* Bug 470958 - [1.8] Unable to convert lambda
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
* Jesper S Moller - Contributions for
* Bug 378674 - "The method can be declared as static" is wrong
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
@@ -75,6 +76,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
@@ -164,6 +166,27 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
}
}
}
+ if (compilerOptions.isAnyEnabled(IrritantSet.UNLIKELY_ARGUMENT_TYPE) && this.binding.isValidBinding()
+ && this.arguments != null) {
+ if (this.arguments.length == 1 && !this.binding.isStatic()) {
+ UnlikelyArgumentCheck argumentChecks = UnlikelyArgumentCheck.determineCheckForNonStaticSingleArgumentMethod(
+ this.argumentTypes[0], currentScope, this.selector, this.actualReceiverType, this.binding.parameters);
+
+ if (argumentChecks != null && argumentChecks.isDangerous(currentScope)) {
+ currentScope.problemReporter().unlikelyArgumentType(this.arguments[0], this.binding,
+ this.argumentTypes[0], argumentChecks.typeToReport, argumentChecks.dangerousMethod);
+ }
+ } else if (this.arguments.length == 2 && this.binding.isStatic()) {
+ UnlikelyArgumentCheck argumentChecks = UnlikelyArgumentCheck.determineCheckForStaticTwoArgumentMethod(
+ this.argumentTypes[1], currentScope, this.selector, this.argumentTypes[0],
+ this.binding.parameters, this.actualReceiverType);
+
+ if (argumentChecks != null && argumentChecks.isDangerous(currentScope)) {
+ currentScope.problemReporter().unlikelyArgumentType(this.arguments[1], this.binding,
+ this.argumentTypes[1], argumentChecks.typeToReport, argumentChecks.dangerousMethod);
+ }
+ }
+ }
if (nonStatic) {
int timeToLive = ((this.bits & ASTNode.InsideExpressionStatement) != 0) ? 3 : 2;
@@ -301,6 +324,7 @@ private int detectAssertionUtility(int argumentIdx) {
}
return 0;
}
+
private FlowInfo analyseBooleanAssertion(BlockScope currentScope, Expression argument,
FlowContext flowContext, FlowInfo flowInfo, boolean wasInsideAssert, boolean passOnTrue)
{
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index fcd74c4cd5..b572490cda 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -61,6 +61,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
@@ -432,6 +433,33 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx
}
}
}
+ if (currentScope.compilerOptions().isAnyEnabled(IrritantSet.UNLIKELY_ARGUMENT_TYPE) && this.binding.isValidBinding()
+ && this.binding != null && this.binding.parameters != null) {
+ if (this.binding.parameters.length == 1
+ && this.descriptor.parameters.length == (this.receiverPrecedesParameters ? 2 : 1)
+ && !this.binding.isStatic()) {
+ final TypeBinding argumentType = this.descriptor.parameters[this.receiverPrecedesParameters ? 1 : 0];
+ final TypeBinding actualReceiverType = this.receiverPrecedesParameters ? this.descriptor.parameters[0] : this.binding.declaringClass;
+ UnlikelyArgumentCheck argumentCheck = UnlikelyArgumentCheck
+ .determineCheckForNonStaticSingleArgumentMethod(argumentType, currentScope, this.selector,
+ actualReceiverType, this.binding.parameters);
+ if (argumentCheck != null && argumentCheck.isDangerous(currentScope)) {
+ currentScope.problemReporter().unlikelyArgumentType(this, this.binding, argumentType,
+ argumentCheck.typeToReport, argumentCheck.dangerousMethod);
+ }
+ } else if (this.binding.parameters.length == 2 && this.descriptor.parameters.length == 2 && this.binding.isStatic()) {
+ final TypeBinding argumentType1 = this.descriptor.parameters[0];
+ final TypeBinding argumentType2 = this.descriptor.parameters[1];
+ UnlikelyArgumentCheck argumentCheck = UnlikelyArgumentCheck
+ .determineCheckForStaticTwoArgumentMethod(argumentType2, currentScope, this.selector,
+ argumentType1, this.binding.parameters, this.receiverType);
+ if (argumentCheck != null && argumentCheck.isDangerous(currentScope)) {
+ currentScope.problemReporter().unlikelyArgumentType(this, this.binding, argumentType2,
+ argumentCheck.typeToReport, argumentCheck.dangerousMethod);
+ }
+ }
+ }
+
manageSyntheticAccessIfNecessary(currentScope, flowInfo);
return flowInfo;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java
new file mode 100644
index 0000000000..de80f94473
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2017 GK Software AG 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stephan Herrmann - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants.DangerousMethod;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+/* @NonNullByDefault */
+public class UnlikelyArgumentCheck {
+ public final DangerousMethod dangerousMethod;
+ public final TypeBinding typeToCheck;
+ public final TypeBinding expectedType;
+ public final TypeBinding typeToReport;
+
+ private UnlikelyArgumentCheck(DangerousMethod dangerousMethod, TypeBinding typeToCheck, TypeBinding expectedType,
+ TypeBinding typeToReport) {
+ this.dangerousMethod = dangerousMethod;
+ this.typeToCheck = typeToCheck;
+ this.expectedType = expectedType;
+ this.typeToReport = typeToReport;
+ }
+
+ /**
+ * Check if the invocation is likely a bug.
+ * @param currentScope
+ * @return false, if the typeToCheck does not seem to related to the expectedType
+ */
+ public boolean isDangerous(BlockScope currentScope) {
+ TypeBinding typeToCheck2 = this.typeToCheck;
+ // take autoboxing into account
+ if (typeToCheck2.isBaseType()) {
+ typeToCheck2 = currentScope.boxing(typeToCheck2);
+ }
+ TypeBinding expectedType2 = this.expectedType;
+ if (expectedType2.isBaseType()) { // can happen for the first parameter of java.util.Object.equals
+ expectedType2 = currentScope.boxing(expectedType2);
+ }
+ if(this.dangerousMethod != DangerousMethod.Equals && currentScope.compilerOptions().reportUnlikelyCollectionMethodArgumentTypeStrict) {
+ return !typeToCheck2.isCompatibleWith(expectedType2, currentScope);
+ }
+ // unless both types are true type variables (not captures), take the erasure of both.
+ if (typeToCheck2.isCapture() || !typeToCheck2.isTypeVariable() || expectedType2.isCapture()
+ || !expectedType2.isTypeVariable()) {
+ typeToCheck2 = typeToCheck2.erasure();
+ expectedType2 = expectedType2.erasure();
+ }
+ return !typeToCheck2.isCompatibleWith(expectedType2, currentScope)
+ && !expectedType2.isCompatibleWith(typeToCheck2, currentScope);
+ }
+
+ /**
+ * When targeting a well-known dangerous method, returns an UnlikelyArgumentCheck object that contains the types to
+ * check against each other and to report
+ */
+ public static /* @Nullable */ UnlikelyArgumentCheck determineCheckForNonStaticSingleArgumentMethod(
+ TypeBinding argumentType, Scope scope, char[] selector, TypeBinding actualReceiverType,
+ TypeBinding[] parameters) {
+ // detecting only methods with a single argument, typed either as Object or as Collection:
+ if (parameters.length != 1)
+ return null;
+ int paramTypeId = parameters[0].original().id;
+ if (paramTypeId != TypeIds.T_JavaLangObject && paramTypeId != TypeIds.T_JavaUtilCollection)
+ return null;
+
+ // check selectors before typeBits as to avoid unnecessary super-traversals for the receiver type
+ DangerousMethod suspect = DangerousMethod.detectSelector(selector);
+ if (suspect == null)
+ return null;
+
+ if (actualReceiverType.hasTypeBit(TypeIds.BitMap)) {
+ if (paramTypeId == TypeIds.T_JavaLangObject) {
+ switch (suspect) {
+ case ContainsKey:
+ case Get:
+ case Remove:
+ // map operations taking a key
+ ReferenceBinding mapType = actualReceiverType
+ .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilMap, false);
+ if (mapType != null && mapType.isParameterizedType())
+ return new UnlikelyArgumentCheck(suspect, argumentType,
+ ((ParameterizedTypeBinding) mapType).typeArguments()[0], mapType);
+ break;
+ case ContainsValue:
+ // map operation taking a value
+ mapType = actualReceiverType.findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilMap, false);
+ if (mapType != null && mapType.isParameterizedType())
+ return new UnlikelyArgumentCheck(suspect, argumentType,
+ ((ParameterizedTypeBinding) mapType).typeArguments()[1], mapType);
+ break;
+ default: // no other suspects are detected in java.util.Map
+ }
+ }
+ }
+ if (actualReceiverType.hasTypeBit(TypeIds.BitCollection)) {
+ if (paramTypeId == TypeIds.T_JavaLangObject) {
+ switch (suspect) {
+ case Remove:
+ case Contains:
+ // collection operations taking a single element
+ ReferenceBinding collectionType = actualReceiverType
+ .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false);
+ if (collectionType != null && collectionType.isParameterizedType())
+ return new UnlikelyArgumentCheck(suspect, argumentType,
+ ((ParameterizedTypeBinding) collectionType).typeArguments()[0], collectionType);
+ break;
+ default: // no other suspects with Object-parameter are detected in java.util.Collection
+ }
+ } else if (paramTypeId == TypeIds.T_JavaUtilCollection) {
+ switch (suspect) {
+ case RemoveAll:
+ case ContainsAll:
+ case RetainAll:
+ // collection operations taking another collection
+ ReferenceBinding collectionType = actualReceiverType
+ .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false);
+ ReferenceBinding argumentCollectionType = argumentType
+ .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false);
+ if (collectionType != null && argumentCollectionType != null
+ && argumentCollectionType.isParameterizedTypeWithActualArguments()) {
+ return new UnlikelyArgumentCheck(suspect,
+ ((ParameterizedTypeBinding) argumentCollectionType).typeArguments()[0],
+ ((ParameterizedTypeBinding) collectionType).typeArguments()[0], collectionType);
+ }
+ break;
+ default: // no other suspects with Collection-parameter are detected in java.util.Collection
+ }
+ }
+ if (actualReceiverType.hasTypeBit(TypeIds.BitList)) {
+ if (paramTypeId == TypeIds.T_JavaLangObject) {
+ switch (suspect) {
+ case IndexOf:
+ case LastIndexOf:
+ // list operations taking a single element
+ ReferenceBinding listType = actualReceiverType
+ .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilList, false);
+ if (listType != null && listType.isParameterizedType())
+ return new UnlikelyArgumentCheck(suspect, argumentType,
+ ((ParameterizedTypeBinding) listType).typeArguments()[0], listType);
+ break;
+ default: // no other suspects are detected in java.util.List
+ }
+ }
+ }
+ }
+ if (paramTypeId == TypeIds.T_JavaLangObject && suspect == DangerousMethod.Equals) {
+ return new UnlikelyArgumentCheck(suspect, argumentType, actualReceiverType, actualReceiverType);
+ }
+ return null; // not replacing
+ }
+ public static /* @Nullable */ UnlikelyArgumentCheck determineCheckForStaticTwoArgumentMethod(
+ TypeBinding secondParameter, Scope scope, char[] selector, TypeBinding firstParameter,
+ TypeBinding[] parameters, TypeBinding actualReceiverType) {
+ // detecting only methods with two arguments, both typed as Object:
+ if (parameters.length != 2)
+ return null;
+ int paramTypeId1 = parameters[0].original().id;
+ int paramTypeId2 = parameters[1].original().id;
+
+ if (paramTypeId1 != TypeIds.T_JavaLangObject || paramTypeId2 != TypeIds.T_JavaLangObject)
+ return null;
+
+ // check selectors before typeBits as to avoid unnecessary super-traversals for the receiver type
+ DangerousMethod suspect = DangerousMethod.detectSelector(selector);
+ if (suspect == null)
+ return null;
+
+ if (actualReceiverType.id == TypeIds.T_JavaUtilObjects && suspect == DangerousMethod.Equals) {
+ return new UnlikelyArgumentCheck(suspect, secondParameter, firstParameter, firstParameter);
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index 22c2272429..a0cc71d403 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -20,6 +20,7 @@
* bug 381443 - [compiler][null] Allow parameter widening from @NonNull to unannotated
* bug 383368 - [compiler][null] syntactic null analysis for field references
* Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
* Jesper Steen Moller - Contributions for
* bug 404146 - [1.7][compiler] nested try-catch-finally-blocks leads to unrunnable Java byte code
* bug 407297 - [1.8][compiler] Control generation of parameter names by option
@@ -161,9 +162,11 @@ public class CompilerOptions {
public static final String OPTION_ReportMethodCanBeStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic"; //$NON-NLS-1$
public static final String OPTION_ReportMethodCanBePotentiallyStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic"; //$NON-NLS-1$
public static final String OPTION_ReportRedundantSpecificationOfTypeArguments = "org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments"; //$NON-NLS-1$
+
public static final String OPTION_ReportUnclosedCloseable = "org.eclipse.jdt.core.compiler.problem.unclosedCloseable"; //$NON-NLS-1$
public static final String OPTION_ReportPotentiallyUnclosedCloseable = "org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable"; //$NON-NLS-1$
public static final String OPTION_ReportExplicitlyClosedAutoCloseable = "org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable"; //$NON-NLS-1$
+
public static final String OPTION_ReportNullSpecViolation = "org.eclipse.jdt.core.compiler.problem.nullSpecViolation"; //$NON-NLS-1$
public static final String OPTION_ReportNullAnnotationInferenceConflict = "org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict"; //$NON-NLS-1$
public static final String OPTION_ReportNullUncheckedConversion = "org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion"; //$NON-NLS-1$
@@ -187,6 +190,10 @@ public class CompilerOptions {
public static final String OPTION_PessimisticNullAnalysisForFreeTypeVariables = "org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables"; //$NON-NLS-1$
public static final String OPTION_ReportNonNullTypeVariableFromLegacyInvocation = "org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation"; //$NON-NLS-1$
+ public static final String OPTION_ReportUnlikelyCollectionMethodArgumentType = "org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType"; //$NON-NLS-1$
+ public static final String OPTION_ReportUnlikelyCollectionMethodArgumentTypeStrict = "org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict"; //$NON-NLS-1$
+ public static final String OPTION_ReportUnlikelyEqualsArgumentType = "org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType"; //$NON-NLS-1$
+
/**
* Possible values for configurable options
*/
@@ -309,6 +316,8 @@ public class CompilerOptions {
public static final int UnusedExceptionParameter = IrritantSet.GROUP2 | ASTNode.Bit19;
public static final int PessimisticNullAnalysisForFreeTypeVariables = IrritantSet.GROUP2 | ASTNode.Bit20;
public static final int NonNullTypeVariableFromLegacyInvocation = IrritantSet.GROUP2 | ASTNode.Bit21;
+ public static final int UnlikelyCollectionMethodArgumentType = IrritantSet.GROUP2 | ASTNode.Bit22;
+ public static final int UnlikelyEqualsArgumentType = IrritantSet.GROUP2 | ASTNode.Bit23;
// Severity level for handlers
/**
@@ -328,12 +337,12 @@ public class CompilerOptions {
protected IrritantSet infoThreshold;
/**
- * Default settings are to be defined in {@lnk CompilerOptions#resetDefaults()}
+ * Default settings are to be defined in {@link CompilerOptions#resetDefaults()}
*/
/** Classfile debug information, may contain source file name, line numbers, local variable tables, etc... */
public int produceDebugAttributes;
- /** Classfile method patameters information as per JEP 118... */
+ /** Classfile method parameters information as per JEP 118... */
public boolean produceMethodParameters;
/** Indicates whether generic signature should be generated for lambda expressions */
public boolean generateGenericSignatureForLambdaExpressions;
@@ -468,6 +477,9 @@ public class CompilerOptions {
/** Should missing enum cases be reported even if a default case exists in the same switch? */
public boolean reportMissingEnumCaseDespiteDefault;
+ /** When checking for unlikely argument types of of Map.get() et al, perform strict analysis against the expected type */
+ public boolean reportUnlikelyCollectionMethodArgumentTypeStrict;
+
/** Should the compiler tolerate illegal ambiguous varargs invocation in compliance < 1.7
* to be bug compatible with javac? (bug 383780) */
public static boolean tolerateIllegalAmbiguousVarargsInvocation;
@@ -493,7 +505,6 @@ public class CompilerOptions {
/** Not directly configurable, derived from other options by LookupEnvironment.usesNullTypeAnnotations() */
public Boolean useNullTypeAnnotations = null;
-
// keep in sync with warningTokenToIrritant and warningTokenFromIrritant
public final static String[] warningTokens = {
@@ -519,6 +530,7 @@ public class CompilerOptions {
"synthetic-access", //$NON-NLS-1$
"sync-override", //$NON-NLS-1$
"unchecked", //$NON-NLS-1$
+ "unlikely-arg-type", //$NON-NLS-1$
"unqualified-field-access", //$NON-NLS-1$
"unused", //$NON-NLS-1$
};
@@ -714,6 +726,10 @@ public class CompilerOptions {
return OPTION_PessimisticNullAnalysisForFreeTypeVariables;
case NonNullTypeVariableFromLegacyInvocation:
return OPTION_ReportNonNullTypeVariableFromLegacyInvocation;
+ case UnlikelyCollectionMethodArgumentType:
+ return OPTION_ReportUnlikelyCollectionMethodArgumentType;
+ case UnlikelyEqualsArgumentType:
+ return OPTION_ReportUnlikelyEqualsArgumentType;
}
return null;
}
@@ -905,7 +921,9 @@ public class CompilerOptions {
OPTION_SyntacticNullAnalysisForFields,
OPTION_ReportUnusedTypeParameter,
OPTION_InheritNullAnnotations,
- OPTION_ReportNonnullParameterAnnotationDropped
+ OPTION_ReportNonnullParameterAnnotationDropped,
+ OPTION_ReportUnlikelyCollectionMethodArgumentType,
+ OPTION_ReportUnlikelyEqualsArgumentType,
};
return result;
}
@@ -997,6 +1015,9 @@ public class CompilerOptions {
return "javadoc"; //$NON-NLS-1$
case MissingSynchronizedModifierInInheritedMethod:
return "sync-override"; //$NON-NLS-1$
+ case UnlikelyEqualsArgumentType:
+ case UnlikelyCollectionMethodArgumentType:
+ return "unlikely-arg-type"; //$NON-NLS-1$
}
return null;
}
@@ -1077,6 +1098,8 @@ public class CompilerOptions {
return IrritantSet.UNCHECKED;
if ("unqualified-field-access".equals(warningToken)) //$NON-NLS-1$
return IrritantSet.UNQUALIFIED_FIELD_ACCESS;
+ if ("unlikely-arg-type".equals(warningToken)) //$NON-NLS-1$
+ return IrritantSet.UNLIKELY_ARGUMENT_TYPE;
break;
}
return null;
@@ -1222,6 +1245,9 @@ public class CompilerOptions {
optionsMap.put(OPTION_ReportUninternedIdentityComparison, this.complainOnUninternedIdentityComparison ? ENABLED : DISABLED);
optionsMap.put(OPTION_PessimisticNullAnalysisForFreeTypeVariables, getSeverityString(PessimisticNullAnalysisForFreeTypeVariables));
optionsMap.put(OPTION_ReportNonNullTypeVariableFromLegacyInvocation, getSeverityString(NonNullTypeVariableFromLegacyInvocation));
+ optionsMap.put(OPTION_ReportUnlikelyCollectionMethodArgumentType, getSeverityString(UnlikelyCollectionMethodArgumentType));
+ optionsMap.put(OPTION_ReportUnlikelyCollectionMethodArgumentTypeStrict, this.reportUnlikelyCollectionMethodArgumentTypeStrict ? ENABLED : DISABLED);
+ optionsMap.put(OPTION_ReportUnlikelyEqualsArgumentType, getSeverityString(UnlikelyEqualsArgumentType));
return optionsMap;
}
@@ -1726,6 +1752,11 @@ public class CompilerOptions {
if ((optionValue = optionsMap.get(OPTION_ReportPotentiallyUnclosedCloseable)) != null) updateSeverity(PotentiallyUnclosedCloseable, optionValue);
if ((optionValue = optionsMap.get(OPTION_ReportExplicitlyClosedAutoCloseable)) != null) updateSeverity(ExplicitlyClosedAutoCloseable, optionValue);
if ((optionValue = optionsMap.get(OPTION_ReportUnusedTypeParameter)) != null) updateSeverity(UnusedTypeParameter, optionValue);
+ if ((optionValue = optionsMap.get(OPTION_ReportUnlikelyCollectionMethodArgumentType)) != null) updateSeverity(UnlikelyCollectionMethodArgumentType, optionValue);
+ if ((optionValue = optionsMap.get(OPTION_ReportUnlikelyCollectionMethodArgumentTypeStrict)) != null) {
+ this.reportUnlikelyCollectionMethodArgumentTypeStrict = ENABLED.equals(optionValue);
+ }
+ if ((optionValue = optionsMap.get(OPTION_ReportUnlikelyEqualsArgumentType)) != null) updateSeverity(UnlikelyEqualsArgumentType, optionValue);
if (getSeverity(UnclosedCloseable) == ProblemSeverities.Ignore
&& getSeverity(PotentiallyUnclosedCloseable) == ProblemSeverities.Ignore
&& getSeverity(ExplicitlyClosedAutoCloseable) == ProblemSeverities.Ignore) {
@@ -2053,6 +2084,9 @@ public class CompilerOptions {
buf.append("\n\t- Unused Type Parameter: ").append(getSeverityString(UnusedTypeParameter)); //$NON-NLS-1$
buf.append("\n\t- pessimistic null analysis for free type variables: ").append(getSeverityString(PessimisticNullAnalysisForFreeTypeVariables)); //$NON-NLS-1$
buf.append("\n\t- report unsafe nonnull return from legacy method: ").append(getSeverityString(NonNullTypeVariableFromLegacyInvocation)); //$NON-NLS-1$
+ buf.append("\n\t- unlikely argument type for collection methods: ").append(getSeverityString(UnlikelyCollectionMethodArgumentType)); //$NON-NLS-1$
+ buf.append("\n\t- unlikely argument type for collection methods, strict check against expected type: ").append(this.reportUnlikelyCollectionMethodArgumentTypeStrict ? ENABLED : DISABLED); //$NON-NLS-1$
+ buf.append("\n\t- unlikely argument types for equals(): ").append(getSeverityString(UnlikelyEqualsArgumentType)); //$NON-NLS-1$
return buf.toString();
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
index 280a502ed0..8ba156b86a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -15,6 +15,7 @@
* bug 374605 - Unreasonable warning for enum-based switch statements
* bug 381443 - [compiler][null] Allow parameter widening from @NonNull to unannotated
* Bug 441208 - [1.8][null]SuppressWarnings("null") does not suppress / marked Unnecessary
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.impl;
@@ -67,12 +68,18 @@ public class IrritantSet {
public static final IrritantSet UNCHECKED = new IrritantSet(CompilerOptions.UncheckedTypeOperation);
public static final IrritantSet UNQUALIFIED_FIELD_ACCESS = new IrritantSet(CompilerOptions.UnqualifiedFieldAccess);
public static final IrritantSet RESOURCE = new IrritantSet(CompilerOptions.UnclosedCloseable);
+ public static final IrritantSet UNLIKELY_ARGUMENT_TYPE = new IrritantSet(CompilerOptions.UnlikelyCollectionMethodArgumentType);
public static final IrritantSet JAVADOC = new IrritantSet(CompilerOptions.InvalidJavadoc);
public static final IrritantSet COMPILER_DEFAULT_ERRORS = new IrritantSet(0); // no optional error by default
public static final IrritantSet COMPILER_DEFAULT_WARNINGS = new IrritantSet(0); // see static initializer below
public static final IrritantSet COMPILER_DEFAULT_INFOS = new IrritantSet(0); // As of now, no default values
static {
+ COMPILER_DEFAULT_INFOS
+ // group-2 infos enabled by default
+ .set(
+ CompilerOptions.UnlikelyEqualsArgumentType);
+
COMPILER_DEFAULT_WARNINGS
// group-0 warnings enabled by default
.set(
@@ -117,7 +124,8 @@ public class IrritantSet {
|CompilerOptions.RedundantNullAnnotation
|CompilerOptions.NonnullParameterAnnotationDropped
|CompilerOptions.PessimisticNullAnalysisForFreeTypeVariables
- |CompilerOptions.NonNullTypeVariableFromLegacyInvocation);
+ |CompilerOptions.NonNullTypeVariableFromLegacyInvocation
+ |CompilerOptions.UnlikelyCollectionMethodArgumentType);
// default errors IF AnnotationBasedNullAnalysis is enabled:
COMPILER_DEFAULT_ERRORS.set(
CompilerOptions.NullSpecViolation
@@ -169,6 +177,9 @@ public class IrritantSet {
JAVADOC
.set(CompilerOptions.MissingJavadocComments)
.set(CompilerOptions.MissingJavadocTags);
+
+ UNLIKELY_ARGUMENT_TYPE
+ .set(CompilerOptions.UnlikelyEqualsArgumentType);
}
// Internal state
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index 96ba4afe66..a128e232af 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -35,6 +35,7 @@
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
* Bug 446442 - [1.8] merge null annotations from super methods
* Bug 456532 - [1.8][null] ReferenceBinding.appendNullAnnotation() includes phantom annotations in error messages
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
* Jesper S Moller - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
@@ -503,13 +504,27 @@ public void computeId() {
if (CharOperation.equals(packageName, TypeConstants.UTIL)) {
switch (typeName[0]) {
case 'C' :
- if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_COLLECTION[2]))
+ if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_COLLECTION[2])) {
this.id = TypeIds.T_JavaUtilCollection;
+ this.typeBits |= TypeIds.BitCollection;
+ }
return;
case 'I' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_ITERATOR[2]))
this.id = TypeIds.T_JavaUtilIterator;
return;
+ case 'L' :
+ if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_LIST[2])) {
+ this.id = TypeIds.T_JavaUtilList;
+ this.typeBits |= TypeIds.BitList;
+ }
+ return;
+ case 'M' :
+ if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_MAP[2])) {
+ this.id = TypeIds.T_JavaUtilMap;
+ this.typeBits |= TypeIds.BitMap;
+ }
+ return;
case 'O' :
if (CharOperation.equals(typeName, TypeConstants.JAVA_UTIL_OBJECTS[2]))
this.id = TypeIds.T_JavaUtilObjects;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index d37a9d0160..5f5360a6df 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 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 @@
* Bug 427199 - [1.8][resource] avoid resource leak warnings on Streams that have no resource
* Bug 425183 - [1.8][inference] make CaptureBinding18 safe
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
* Jesper S Moller - Contributions for
* Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
* Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
@@ -27,6 +28,8 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
+import org.eclipse.jdt.core.compiler.CharOperation;
+
// TODO should rename into TypeNames (once extracted last non name constants)
public interface TypeConstants {
@@ -160,6 +163,7 @@ public interface TypeConstants {
char[][] JAVA_UTIL_COLLECTION = {JAVA, UTIL, "Collection".toCharArray()}; //$NON-NLS-1$
char[][] JAVA_UTIL_ITERATOR = {JAVA, UTIL, "Iterator".toCharArray()}; //$NON-NLS-1$
char[][] JAVA_UTIL_OBJECTS = {JAVA, UTIL, "Objects".toCharArray()}; //$NON-NLS-1$
+ char[][] JAVA_UTIL_LIST = {JAVA, UTIL, "List".toCharArray()}; //$NON-NLS-1$
char[][] JAVA_LANG_DEPRECATED = {JAVA, LANG, "Deprecated".toCharArray()}; //$NON-NLS-1$
char[][] JAVA_LANG_ANNOTATION_DOCUMENTED = {JAVA, LANG, ANNOTATION, "Documented".toCharArray()}; //$NON-NLS-1$
char[][] JAVA_LANG_ANNOTATION_INHERITED = {JAVA, LANG, ANNOTATION, "Inherited".toCharArray()}; //$NON-NLS-1$
@@ -333,6 +337,75 @@ public interface TypeConstants {
char[][] COM_GOOGLE_INJECT_INJECT = new char[][] {COM, GOOGLE, INJECT_PACKAGE, INJECT_TYPE };
// detail for the above:
char[] OPTIONAL = "optional".toCharArray(); //$NON-NLS-1$
+
+ // well-known methods with "dangerous" signatures:
+ char[][] JAVA_UTIL_MAP = new char[][] { JAVA, UTIL, "Map".toCharArray() }; //$NON-NLS-1$
+ char[] GET = "get".toCharArray(); //$NON-NLS-1$
+ char[] REMOVE = "remove".toCharArray(); //$NON-NLS-1$
+ char[] REMOVE_ALL = "removeAll".toCharArray(); //$NON-NLS-1$
+ char[] CONTAINS_ALL = "containsAll".toCharArray(); //$NON-NLS-1$
+ char[] RETAIN_ALL = "retainAll".toCharArray(); //$NON-NLS-1$
+ char[] CONTAINS_KEY = "containsKey".toCharArray(); //$NON-NLS-1$
+ char[] CONTAINS_VALUE = "containsValue".toCharArray(); //$NON-NLS-1$
+ // for Collection.contains:
+ char[] CONTAINS = "contains".toCharArray(); //$NON-NLS-1$
+ // for List.*indexOf:
+ char[] INDEX_OF = "indexOf".toCharArray(); //$NON-NLS-1$
+ char[] LAST_INDEX_OF = "lastIndexOf".toCharArray(); //$NON-NLS-1$
+ enum DangerousMethod {
+ // Collection:
+ Contains, Remove, RemoveAll, ContainsAll, RetainAll,
+ // Map:
+ Get, ContainsKey, ContainsValue,
+ // List:
+ IndexOf, LastIndexOf,
+ // Object:
+ Equals;
+
+ public static DangerousMethod detectSelector(char[] selector) {
+ switch (selector[0]) {
+ case 'r':
+ if (CharOperation.prefixEquals(TypeConstants.REMOVE, selector)) {
+ if (CharOperation.equals(selector, TypeConstants.REMOVE))
+ return DangerousMethod.Remove;
+ else if (CharOperation.equals(selector, TypeConstants.REMOVE_ALL))
+ return DangerousMethod.RemoveAll;
+ } else if (CharOperation.equals(selector, TypeConstants.RETAIN_ALL)) {
+ return DangerousMethod.RetainAll;
+ }
+ break;
+ case 'c':
+ if (CharOperation.prefixEquals(TypeConstants.CONTAINS, selector)) {
+ if (CharOperation.equals(selector, TypeConstants.CONTAINS))
+ return DangerousMethod.Contains;
+ else if (CharOperation.equals(selector, TypeConstants.CONTAINS_ALL))
+ return DangerousMethod.ContainsAll;
+ else if (CharOperation.equals(selector, TypeConstants.CONTAINS_KEY))
+ return DangerousMethod.ContainsKey;
+ else if (CharOperation.equals(selector, TypeConstants.CONTAINS_VALUE))
+ return DangerousMethod.ContainsValue;
+ }
+ break;
+ case 'g':
+ if (CharOperation.equals(selector, TypeConstants.GET))
+ return DangerousMethod.Get;
+ break;
+ case 'i':
+ if (CharOperation.equals(selector, TypeConstants.INDEX_OF))
+ return DangerousMethod.IndexOf;
+ break;
+ case 'l':
+ if (CharOperation.equals(selector, TypeConstants.LAST_INDEX_OF))
+ return DangerousMethod.LastIndexOf;
+ break;
+ case 'e':
+ if (CharOperation.equals(selector, TypeConstants.EQUALS))
+ return DangerousMethod.Equals;
+ break;
+ }
+ return null;
+ }
+ }
// Spring @Autowired annotation
char [] AUTOWIRED = "Autowired".toCharArray(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
index 7749b66f35..425672f525 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
@@ -14,6 +14,7 @@
* bug 358903 - Filter practically unimportant resource leak warnings
* bug 400421 - [compiler] Null analysis for fields does not take @com.google.inject.Inject into account
* bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
* Ulrich Grave <ulrich.grave@gmx.de> - Contributions for
@@ -132,6 +133,11 @@ public interface TypeIds {
// Java 8 - JEP 120
final int T_JavaLangAnnotationRepeatable = 90;
+
+ // classes with methods with "dangerous" signatures:
+ final int T_JavaUtilMap = 91;
+ final int T_JavaUtilList = 92;
+
// If you add new type id, make sure to bump up T_LastWellKnownTypeId if there is a cross over.
final int T_LastWellKnownTypeId = 128;
@@ -253,8 +259,17 @@ public interface TypeIds {
final int BitNonNullByDefaultAnnotation = 128;
final int BitAnyNullAnnotation = BitNonNullAnnotation | BitNullableAnnotation | BitNonNullByDefaultAnnotation;
+ /** Mark subtypes of Map to analyze dangerous get/remove et al. */
+ final int BitMap = 256;
+
+ /** Mark subtypes of Collection to analyze dangerous contains/remove. */
+ final int BitCollection = 512;
+
+ /** Mark subtypes of List to analyze dangerous indexOf. */
+ final int BitList = 1024;
+
/**
* Set of type bits that should be inherited by any sub types.
*/
- final int InheritableBits = BitAutoCloseable | BitCloseable | BitUninternedType;
+ final int InheritableBits = BitAutoCloseable | BitCloseable | BitUninternedType | BitMap | BitCollection | BitList ;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index 3773f15337..5d40ddfa8e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -59,6 +59,7 @@
* Bug 458361 - [1.8][null] reconciler throws NPE in ProblemReporter.illegalReturnRedefinition()
* Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf()
* Bug 461878 - [1.7][1.8][compiler][null] ECJ compiler does not allow to use null annotations on annotations
+ * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
@@ -177,6 +178,7 @@ import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants.DangerousMethod;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
@@ -609,6 +611,11 @@ public static int getIrritant(int problemID) {
case IProblem.UnusedTypeParameter:
return CompilerOptions.UnusedTypeParameter;
+
+ case IProblem.UnlikelyCollectionMethodArgumentType:
+ return CompilerOptions.UnlikelyCollectionMethodArgumentType;
+ case IProblem.UnlikelyEqualsArgumentType:
+ return CompilerOptions.UnlikelyEqualsArgumentType;
}
return 0;
}
@@ -668,6 +675,8 @@ public static int getProblemCategory(int severity, int problemID) {
case CompilerOptions.PotentiallyUnclosedCloseable :
case CompilerOptions.PessimisticNullAnalysisForFreeTypeVariables :
case CompilerOptions.NonNullTypeVariableFromLegacyInvocation :
+ case CompilerOptions.UnlikelyCollectionMethodArgumentType :
+ case CompilerOptions.UnlikelyEqualsArgumentType:
return CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM;
case CompilerOptions.OverriddenPackageDefaultMethod :
@@ -10472,4 +10481,23 @@ public void invalidTypeArguments(TypeReference[] typeReference) {
typeReference[0].sourceStart,
typeReference[typeReference.length - 1].sourceEnd);
}
+
+public void unlikelyArgumentType(Expression argument, MethodBinding method, TypeBinding argumentType,
+ TypeBinding receiverType, DangerousMethod dangerousMethod)
+{
+ this.handle(
+ dangerousMethod == DangerousMethod.Equals ? IProblem.UnlikelyEqualsArgumentType : IProblem.UnlikelyCollectionMethodArgumentType,
+ new String[] {
+ new String(argumentType.readableName()),
+ new String(method.readableName()),
+ new String(receiverType.readableName())
+ },
+ new String[] {
+ new String(argumentType.shortReadableName()),
+ new String(method.shortReadableName()),
+ new String(receiverType.shortReadableName())
+ },
+ argument.sourceStart,
+ argument.sourceEnd);
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index fbd87c98a2..9467accb5b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -42,6 +42,7 @@
# Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type
# Bug 438467 - [compiler][null] Better error position for "The method _ cannot implement the corresponding method _ due to incompatible nullness constraints"
# Bug 458361 - [1.8][null] reconciler throws NPE in ProblemReporter.illegalReturnRedefinition()
+# Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al.
# Jesper S Moller <jesper@selskabet.org> - Contributions for
# bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
# bug 384567 - [1.5][compiler] Compiler accepts illegal modifiers on package declaration
@@ -867,6 +868,10 @@
1100 = Problem detected during type inference: {0}
#1101 is already used up but deprecated
1102 = At least one of the problems in category ''{0}'' is not analysed due to a compiler option being ignored
+# more programming problems:
+1200 = Unlikely argument type {0} for {1} on a {2}
+1201 = Unlikely argument type for equals(): {0} seems to be unrelated to {2}
+
### ELABORATIONS
## Access restrictions
78592 = The type ''{1}'' is not API (restriction on classpath entry ''{0}'')
@@ -880,4 +885,4 @@
78602 = The constructor ''{1}'' is not API (restriction on required library ''{0}'')
78604 = The method ''{2}.{1}'' is not API (restriction on classpath entry ''{0}'')
78606 = The method ''{2}.{1}'' is not API (restriction on required library ''{0}'')
-78605 = The method ''{2}.{1}'' is not API (restriction on required project ''{0}'') \ No newline at end of file
+78605 = The method ''{2}.{1}'' is not API (restriction on required project ''{0}'')
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index 89a651acd3..ffb80ea513 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -98,6 +98,8 @@
* COMPILER_INHERIT_NULL_ANNOTATIONS
* COMPILER_PB_NONNULL_PARAMETER_ANNOTATION_DROPPED
* COMPILER_PB_SYNTACTIC_NULL_ANALYSIS_FOR_FIELDS
+ * COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE
+ * COMPILER_PB_UNLIKELY_EQUALS_ARGUMENT_TYPE
* Jesper S Moller - Contributions for bug 381345 : [1.8] Take care of the Java 8 major version
* - added the following constants:
* COMPILER_CODEGEN_METHOD_PARAMETERS_ATTR
@@ -1514,6 +1516,60 @@ public final class JavaCore extends Plugin {
* @category CompilerOptionID
*/
public static final String COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE = PLUGIN_ID + ".compiler.problem.explicitlyClosedAutoCloseable"; //$NON-NLS-1$
+
+ /**
+ * Compiler option ID: Reporting a method invocation providing an argument of an unlikely type.
+ * <p>When enabled, the compiler will issue an error or warning when certain well-known Collection methods
+ * that take an 'Object', like e.g. {@link Map#get(Object)}, are used with an argument type
+ * that seems to be not related to the corresponding type argument of the Collection.</p>
+ * <p>By default, this analysis will apply some heuristics to determine whether or not two
+ * types may or may not be related, which can be changed via option
+ * {@link #COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE_STRICT}.</p>
+ * <dl>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType"</code></dd>
+ * <dt>Possible values:</dt><dd><code>{ "error", "warning", "info", "ignore" }</code></dd>
+ * <dt>Default:</dt><dd><code>"warning"</code></dd>
+ * </dl>
+ * @since 3.13
+ * @category CompilerOptionID
+ */
+ public static final String COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE = PLUGIN_ID + ".compiler.problem.unlikelyCollectionMethodArgumentType"; //$NON-NLS-1$
+
+ /**
+ * Compiler option ID: Perform strict analysis against the expected type of collection methods.
+ * <p>This is a sub-option of {@link #COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE},
+ * which will replace the heuristics with strict compatibility checks,
+ * i.e., each argument that is not strictly compatible with the expected type will trigger an error or warning.</p>
+ * <p>This option has no effect if {@link #COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE} is set to <code>"ignore"</code>.</p>
+ * <dl>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict"</code></dd>
+ * <dt>Possible values:</dt><dd><code>{ "enabled", "disabled" }</code></dd>
+ * <dt>Default:</dt><dd><code>"disabled"</code></dd>
+ * </dl>
+ * @since 3.13
+ * @category CompilerOptionID
+ */
+ public static final String COMPILER_PB_UNLIKELY_COLLECTION_METHOD_ARGUMENT_TYPE_STRICT = PLUGIN_ID + ".compiler.problem.unlikelyCollectionMethodArgumentTypeStrict"; //$NON-NLS-1$
+
+ /**
+ * Compiler option ID: Reporting a method invocation providing an argument of an unlikely type to method 'equals'.
+ * <p>
+ * When enabled, the compiler will issue an error or warning when {@link java.lang.Object#equals(Object)} is used with an argument type
+ * that seems to be not related to the receiver's type, or correspondingly when the arguments of {@link java.util.Objects#equals(Object, Object)}
+ * have types that seem to be not related to each other.
+ * </p>
+ * <dl>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType"</code></dd>
+ * <dt>Possible values:</dt>
+ * <dd><code>{ "error", "warning", "info", "ignore" }</code></dd>
+ * <dt>Default:</dt><dd><code>"info"</code></dd>
+ * </dl>
+ *
+ * @since 3.13
+ * @category CompilerOptionID
+ */
+ public static final String COMPILER_PB_UNLIKELY_EQUALS_ARGUMENT_TYPE = PLUGIN_ID + ".compiler.problem.unlikelyEqualsArgumentType"; //$NON-NLS-1$
+
/**
* Compiler option ID: Annotation-based Null Analysis.
* <p>This option controls whether the compiler will use null annotations for

Back to the top