8237074: Warning when obj.getClass() == SomeItf.class (from State-of-Valhalla)

Jesper Steen Møller jesper at selskabet.org
Tue Jan 21 22:07:30 UTC 2020


Hi list.
 - another patch for review for another (smaller) task opened by Srikanth from the 'State of Valhalla’ writeup.

This patch is for 8237074 [1], where we’d want to catch the case where Optional or Integer migrate from being classes to interfaces, and where existing code tries to query their type by using Object.getClass() and compare with a class literal for something which is now a literal.

I’m sure the wording of the error message and possibly the lint category could be improved by a native English-speaker.

One small quirk: There was a problem with the CheckExamples test not picking up that “// key:”-marker in the test source, so I ended up adding the warning key to "examples.not-yet.txt", which feels like a bit of a hack. I can see there’s a bug JDK-8209907 related to problems with CheckExamples in “lworld", so maybe I’ll examine the reason.

[1]: https://bugs.openjdk.java.net/browse/JDK-8237074

-Jesper

diff -r 9d2ec504577f src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java	Mon Jan 13 17:18:47 2020 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java	Tue Jan 21 23:06:20 2020 +0100
@@ -211,6 +211,11 @@
         FINALLY("finally"),
 
         /**
+         * Warn about the use of interfaces which have previously been classes
+         */
+        INTERFACES("interfaces"),
+
+        /**
          * Warn about module system related issues.
          */
         MODULE("module"),
diff -r 9d2ec504577f src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Jan 13 17:18:47 2020 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jan 21 23:06:20 2020 +0100
@@ -3814,6 +3814,7 @@
                 if (!types.isCastable(left, right, new Warner(tree.pos()))) {
                     log.error(tree.pos(), Errors.IncomparableTypes(left, right));
                 }
+                chk.checkObjectIdentityComparison(tree.pos(), tree, left, right);
             }
 
             chk.checkDivZero(tree.rhs.pos(), operator, right);
diff -r 9d2ec504577f src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Jan 13 17:18:47 2020 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jan 21 23:06:20 2020 +0100
@@ -1045,6 +1045,39 @@
         return varType;
     }
 
+    boolean isApplyGetClass(JCExpression tree) {
+        tree = TreeInfo.skipParens(tree);
+        if (tree.hasTag(APPLY)) {
+            JCMethodInvocation apply = (JCMethodInvocation)tree;
+            Symbol sym = TreeInfo.symbol(apply.meth);
+            return sym.name == names.getClass;
+        }
+        return false;
+    }
+
+    boolean isClassOfSomeInterface(Type someClass) {
+        if (someClass.tsym.flatName() == names.java_lang_Class) {
+            List<Type> arguments = someClass.getTypeArguments();
+            if (arguments.length() == 1) {
+                return arguments.head.isInterface();
+            }
+        }
+        return false;
+    }
+
+    public void checkObjectIdentityComparison(
+            final DiagnosticPosition pos,
+            final JCBinary tree,
+            final Type leftType,
+            final Type rightType) {
+
+        if (isApplyGetClass(tree.lhs) && isClassOfSomeInterface(rightType)) {
+            log.warning(LintCategory.INTERFACES, pos, Warnings.GetClassComparedWithInterface(rightType));
+        } else if (isApplyGetClass(tree.rhs) && isClassOfSomeInterface(leftType)) {
+            log.warning(LintCategory.INTERFACES, pos, Warnings.GetClassComparedWithInterface(leftType));
+        }
+    }
+
     Type checkMethod(final Type mtype,
             final Symbol sym,
             final Env<AttrContext> env,
diff -r 9d2ec504577f src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Jan 13 17:18:47 2020 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Jan 21 23:06:20 2020 +0100
@@ -1778,6 +1778,10 @@
 compiler.warn.incubating.modules=\
     using incubating module(s): {0}
 
+# 0: type
+compiler.warn.get.class.compared.with.interface=\
+    result of calling getClass() compared to class of interface {0}
+
 # 0: symbol, 1: symbol
 compiler.warn.has.been.deprecated=\
     {0} in {1} has been deprecated
diff -r 9d2ec504577f src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Mon Jan 13 17:18:47 2020 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Tue Jan 21 23:06:20 2020 +0100
@@ -203,6 +203,9 @@
 javac.opt.Xlint.desc.finally=\
     Warn about finally clauses that do not terminate normally.
 
+javac.opt.Xlint.desc.interfaces=\
+    Warn about interfaces which may previously have been classes.
+
 javac.opt.Xlint.desc.module=\
     Warn about module system related issues.
 
diff -r 9d2ec504577f test/langtools/tools/javac/diags/examples.not-yet.txt
--- a/test/langtools/tools/javac/diags/examples.not-yet.txt	Mon Jan 13 17:18:47 2020 -0800
+++ b/test/langtools/tools/javac/diags/examples.not-yet.txt	Tue Jan 21 23:06:20 2020 +0100
@@ -109,6 +109,7 @@
 compiler.warn.annotation.method.not.found.reason        # ClassReader
 compiler.warn.big.major.version                         # ClassReader
 compiler.warn.future.attr                               # ClassReader
+compiler.warn.get.class.compared.with.interface         # if this isn't listed here, CheckExamples.java will complain
 compiler.warn.illegal.char.for.encoding
 compiler.warn.incubating.modules                        # requires adjusted classfile
 compiler.warn.invalid.archive.file
diff -r 9d2ec504577f test/langtools/tools/javac/valhalla/lworld-values/CheckInterfaceComparison.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/CheckInterfaceComparison.java	Tue Jan 21 23:06:20 2020 +0100
@@ -0,0 +1,33 @@
+/*
+ * @bug 8237074
+ * @test /nodynamiccopyright/
+ * @summary Result of .getClass() should never be compared to an interface class literal
+ *
+ * @compile/ref=CheckInterfaceComparison.out -XDrawDiagnostics CheckInterfaceComparison.java
+ */
+// key: compiler.warn.get.class.compared.with.interface
+public class CheckInterfaceComparison {
+    public boolean bogusCompareLeft(Object o) { // Should be warned against
+        return (o.getClass()) == Runnable.class;
+    }
+
+    public boolean bogusCompareRight(Object o) { // Should be warned against
+        return Iterable.class == o.getClass();
+    }
+
+    public boolean goodCompareLeft(Object o) { // Is fine, no warning required
+        return o.getClass() == Integer.class;
+    }
+
+    public boolean goodCompareRight(Object o) { // Is fine, no warning required
+        return Long.class == o.getClass();
+    }
+
+    public boolean rawCompareLeft(Object o, Class<?> clazz) { // Is fine, no warning required
+        return o.getClass() == clazz;
+    }
+
+    public boolean rawCompareRight(Object o, Class<?> clazz) { // Is fine, no warning required
+        return clazz == o.getClass();
+    }
+}
diff -r 9d2ec504577f test/langtools/tools/javac/valhalla/lworld-values/CheckInterfaceComparison.out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/CheckInterfaceComparison.out	Tue Jan 21 23:06:20 2020 +0100
@@ -0,0 +1,3 @@
+CheckInterfaceComparison.java:10:31: compiler.warn.get.class.compared.with.interface: java.lang.Class<java.lang.Runnable>
+CheckInterfaceComparison.java:14:31: compiler.warn.get.class.compared.with.interface: java.lang.Class<java.lang.Iterable>
+2 warnings



More information about the valhalla-dev mailing list