--- old/make/CompileJavaModules.gmk 2020-08-13 16:19:21.167000000 -0700 +++ new/make/CompileJavaModules.gmk 2020-08-13 16:19:20.527000000 -0700 @@ -76,6 +76,7 @@ ################################################################################ +java.desktop_DISABLED_WARNINGS += missing-declared-ctor java.desktop_DOCLINT += -Xdoclint:all/protected,-reference \ '-Xdoclint/package:java.*,javax.*' java.desktop_COPY += .gif .png .wav .txt .xml .css .pf @@ -298,6 +299,10 @@ ################################################################################ +jdk.accessibility_DISABLED_WARNINGS += missing-declared-ctor + +################################################################################ + jdk.charsets_COPY += .dat ################################################################################ @@ -347,10 +352,19 @@ ################################################################################ +jdk.jartool_DISABLED_WARNINGS += missing-declared-ctor jdk.jartool_JAVAC_FLAGS += -XDstringConcat=inline ################################################################################ +jdk.httpserver_DISABLED_WARNINGS += missing-declared-ctor + +################################################################################ + +jdk.unsupported.desktop_DISABLED_WARNINGS += missing-declared-ctor + +################################################################################ + # No SCTP implementation on Mac OS X or AIX. These classes should be excluded. SCTP_IMPL_CLASSES = \ $(TOPDIR)/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/AssociationChange.java \ --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java 2020-08-13 16:19:22.231000000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java 2020-08-13 16:19:21.595000000 -0700 @@ -211,6 +211,11 @@ FINALLY("finally"), /** + * Warn about compiler generation of a default constructor. + */ + MISSING_DECLARED_CTOR("missing-declared-ctor"), + + /** * Warn about module system related issues. */ MODULE("module"), --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java 2020-08-13 16:19:23.815000000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java 2020-08-13 16:19:23.183000000 -0700 @@ -29,6 +29,7 @@ import java.util.function.Supplier; import javax.lang.model.element.ElementKind; +import javax.lang.model.element.NestingKind; import javax.tools.JavaFileManager; import com.sun.tools.javac.code.*; @@ -649,7 +650,7 @@ if (lint.isEnabled(LintCategory.CAST)) log.warning(LintCategory.CAST, tree.pos(), Warnings.RedundantCast(tree.clazz.type)); - }); + }); } } //where @@ -2366,7 +2367,7 @@ tv.setUpperBound(types.createErrorType(t)); log.error(pos, Errors.CyclicInheritance(t)); } else if (t.hasTag(TYPEVAR)) { - tv = (TypeVar)t; + tv = (TypeVar)t; seen = seen.prepend(tv); for (Type b : types.getBounds(tv)) checkNonCyclic1(pos, b, seen); @@ -3827,6 +3828,59 @@ } } + /** + * Check for a default constructor in an exported package. + */ + void checkDefaultConstructor(ClassSymbol c, DiagnosticPosition pos) { + if (lint.isEnabled(LintCategory.MISSING_DECLARED_CTOR) && + ((c.flags() & (ENUM | RECORD)) == 0) && + !c.isAnonymous() && + ((c.flags() & PUBLIC) != 0) && + Feature.MODULES.allowedInSource(source)) { + NestingKind nestingKind = c.getNestingKind(); + switch (nestingKind) { + case ANONYMOUS, + LOCAL -> {return;} + case TOP_LEVEL -> {;} // No additional checks needed + case MEMBER -> { + // For nested member classes, all the enclosing + // classes must be public. + Symbol owner = c.owner; + while (owner != null && owner.kind == TYP) { + if ((owner.flags() & PUBLIC) == 0) + return; + owner = owner.owner; + } + } + } + + // Only check classes in named packages exported by its module + PackageSymbol pkg = c.packge(); + if (!pkg.isUnnamed()) { + ModuleSymbol modle = pkg.modle; + for (ExportsDirective exportDir : modle.exports) { + // Report warning only if the containing + // package is unconditionally exported + if (exportDir.packge.equals(pkg)) { + if (exportDir.modules == null || exportDir.modules.isEmpty()) { + // Warning may be suppressed by + // annotations; check again for being + // enabled in the deferred context. + deferredLintHandler.report(() -> { + if (lint.isEnabled(LintCategory.MISSING_DECLARED_CTOR)) + log.warning(LintCategory.MISSING_DECLARED_CTOR, + pos, Warnings.MissingDeclaredCtor(c, pkg, modle)); + }); + } else { + return; + } + } + } + } + } + return; + } + private class ConversionWarner extends Warner { final String uncheckedKey; final Type found; --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java 2020-08-13 16:19:25.511000000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java 2020-08-13 16:19:24.879000000 -0700 @@ -1000,6 +1000,7 @@ // Add default constructor if needed. DefaultConstructorHelper helper = getDefaultConstructorHelper(env); if (helper != null) { + chk.checkDefaultConstructor(sym, tree.pos()); defaultConstructor = defaultConstructor(make.at(tree.pos), helper); tree.defs = tree.defs.prepend(defaultConstructor); } --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties 2020-08-13 16:19:27.119000000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties 2020-08-13 16:19:26.491000000 -0700 @@ -1760,6 +1760,10 @@ compiler.warn.dir.path.element.not.directory=\ bad path element "{0}": not a directory +# 0: symbol, 1: symbol, 2: symbol +compiler.warn.missing-declared-ctor=\ + class {0} in exported package {1} of module {2} does not declare any explicit constructors, exposing a default constructor to clients + compiler.warn.finally.cannot.complete=\ finally clause cannot complete normally --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties 2020-08-13 16:19:28.763000000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties 2020-08-13 16:19:28.123000000 -0700 @@ -182,6 +182,9 @@ javac.opt.Xlint.desc.classfile=\ Warn about issues related to classfile contents. +javac.opt.Xlint.desc.missing-declared-ctor=\ + Warn about missing declared constructors in public classes in exported packages. + javac.opt.Xlint.desc.deprecation=\ Warn about use of deprecated items. --- /dev/null 2020-08-01 01:56:10.772000000 -0700 +++ new/test/langtools/tools/javac/diags/examples/WarnDefaultCtor/DefaultCtor.java 2020-08-13 16:19:29.179000000 -0700 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.warn.missing-declared-ctor +// options: -Xlint:missing-declared-ctor --- /dev/null 2020-08-01 01:56:10.772000000 -0700 +++ new/test/langtools/tools/javac/diags/examples/WarnDefaultCtor/modulesourcepath/defaultctor/module-info.java 2020-08-13 16:19:30.375000000 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module defaultctor { + exports pkg; +} --- /dev/null 2020-08-01 01:56:10.772000000 -0700 +++ new/test/langtools/tools/javac/diags/examples/WarnDefaultCtor/modulesourcepath/defaultctor/pkg/Foo.java 2020-08-13 16:19:31.579000000 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +public class Foo { + // No explicit constructor. +} --- /dev/null 2020-08-01 01:56:10.772000000 -0700 +++ new/test/langtools/tools/javac/warnings/DefaultCtor/DefaultCtorWarningToolBox.java 2020-08-13 16:19:32.739000000 -0700 @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8071961 + * @summary Verify expected default constructor warnings are producted or not produced + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask toolbox.TestRunner + * @run main DefaultCtorWarningToolBox + */ + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +import java.io.InputStream; +import java.nio.file.Files; +import java.util.EnumSet; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.Task.Expect; +import toolbox.TestRunner; +import toolbox.ToolBox; + +public class DefaultCtorWarningToolBox extends TestRunner { + + private final ToolBox tb = new ToolBox(); + private final String fileSep = System.getProperty("file.separator"); + + public DefaultCtorWarningToolBox() { + super(System.err); + } + + public static void main(String... args) throws Exception { + new DefaultCtorWarningToolBox().runTests(); + } + + @Test + public void testWithAndWithOutLint(Path base) throws IOException { + Path src = base.resolve("src"); + + tb.writeJavaFiles(src, + MOD_INFO_SRC, + PKG1_BAR_SRC, PKG1_FOO_SRC, + PKG2_BAZ_SRC, PKG2_QUUX_SRC, + PKG3_CORGE_SRC, PKG3_GRAULT_SRC + ); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log; + List expected = List.of(""); + + // Warning disabled, no messages expected + log = new JavacTask(tb) + .options("-Xlint:-missing-declared-ctor", "-Werror") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (!expected.equals(log)) { + throw new AssertionError("Unexpected output: " + log); + } + + expected = + List.of("Foo.java:4:8: compiler.warn.missing-declared-ctor: pkg1.Foo, pkg1, mod", + "Foo.java:12:12: compiler.warn.missing-declared-ctor: pkg1.Foo.FooNest, pkg1, mod", + "Foo.java:16:19: compiler.warn.missing-declared-ctor: pkg1.Foo.StaticFooNest, pkg1, mod", + "3 warnings"); + + // Warning enable, + log = new JavacTask(tb) + .options("-Xlint:missing-declared-ctor", "-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (!expected.equals(log)) { + throw new AssertionError("Unexpected output: " + log); + } + } + + protected void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()).toAbsolutePath() }); + } + + private static final String MOD_INFO_SRC = + """ + module mod { + exports pkg1; + // Do *not* export pkg2. + exports pkg3 to java.base; + } + """; + + private static final String PKG1_BAR_SRC = + """ + package pkg1; + + // Neither the top-level class nor the nested classes should generate + // a warning since Bar is not public. + + // No explicit constructor; use a default. + class Bar { + + // No explicit constructor; use a default. + public class FooNest { + } + + // No explicit constructor; use a default. + public static class StaticFooNest { + } + + // Package-access classes + + // No explicit constructor; use a default. + /*package*/ class PkgFooNest { + } + + // No explicit constructor; use a default. + /*package*/ static class PkgStaticFooNest { + } + // Private classes + + // No explicit constructor; use a default. + private class PrvFooNest { + } + + // No explicit constructor; use a default. + private static class PrvStaticFooNest { + } + } + """; + + private static final String PKG1_FOO_SRC = + """ + package pkg1; + + // No explicit constructor; use a default. + public class Foo { + + /* + * Of the nexted classes, only FooNest and StaticFooNest should + * generate warnings. + */ + + // No explicit constructor; use a default. + public class FooNest { + } + + // No explicit constructor; use a default. + public static class StaticFooNest { + } + + // No explicit constructor; use a default. + @SuppressWarnings("missing-declared-ctor") + public static class SuppressedStaticFooNest { + } + + // Package-access classes + + // No explicit constructor; use a default. + /*package*/ class PkgFooNest { + } + + // No explicit constructor; use a default. + /*package*/ static class PkgStaticFooNest { + } + // Private classes + + // No explicit constructor; use a default. + private class PrvFooNest { + } + + // No explicit constructor; use a default. + private static class PrvStaticFooNest { + } + } + """; + + private static final String PKG2_BAZ_SRC = + """ + package pkg2; + + // None of these classes should generate warnings since pkg2 is not + // exported unconditionally. + + // No explicit constructor; use a default. + public class Baz { + + // No explicit constructor; use a default. + public class FooNest { + } + + // No explicit constructor; use a default. + public static class StaticFooNest { + } + + // Package-access classes + + // No explicit constructor; use a default. + /*package*/ class PkgFooNest { + } + + // No explicit constructor; use a default. + /*package*/ static class PkgStaticFooNest { + } + // Private classes + + // No explicit constructor; use a default. + private class PrvFooNest { + } + + // No explicit constructor; use a default. + private static class PrvStaticFooNest { + } + } + """; + + private static final String PKG2_QUUX_SRC = + """ + package pkg2; + + // Neither the top-level class nor the nested classes should generate + // a warning since Bar is not public. + + // No explicit constructor; use a default. + class Quux { + + // No explicit constructor; use a default. + public class FooNest { + } + + // No explicit constructor; use a default. + public static class StaticFooNest { + } + + // Package-access classes + + // No explicit constructor; use a default. + /*package*/ class PkgFooNest { + } + + // No explicit constructor; use a default. + /*package*/ static class PkgStaticFooNest { + } + // Private classes + + // No explicit constructor; use a default. + private class PrvFooNest { + } + + // No explicit constructor; use a default. + private static class PrvStaticFooNest { + } + } + """; + + private static final String PKG3_CORGE_SRC = + """ + package pkg3; + + // None of these classes should generate warnings since pkg3 is not + // exported unconditionally. + + // No explicit constructor; use a default. + public class Corge { + + // No explicit constructor; use a default. + public class FooNest { + } + + // No explicit constructor; use a default. + public static class StaticFooNest { + } + + // Package-access classes + + // No explicit constructor; use a default. + /*package*/ class PkgFooNest { + } + + // No explicit constructor; use a default. + /*package*/ static class PkgStaticFooNest { + } + // Private classes + + // No explicit constructor; use a default. + private class PrvFooNest { + } + + // No explicit constructor; use a default. + private static class PrvStaticFooNest { + } + } + """; + + private static final String PKG3_GRAULT_SRC = + """ + package pkg3; + + // None of these classes should generate warnings since pkg3 is not + // exported unconditionally. + + // No explicit constructor; use a default. + class Grault { + + // No explicit constructor; use a default. + public class FooNest { + } + + // No explicit constructor; use a default. + public static class StaticFooNest { + } + + // Package-access classes + + // No explicit constructor; use a default. + /*package*/ class PkgFooNest { + } + + // No explicit constructor; use a default. + /*package*/ static class PkgStaticFooNest { + } + // Private classes + + // No explicit constructor; use a default. + private class PrvFooNest { + } + + // No explicit constructor; use a default. + private static class PrvStaticFooNest { + } + } + """; +} --- /dev/null 2020-08-01 01:56:10.772000000 -0700 +++ new/test/langtools/tools/javac/warnings/DefaultCtor/NoWarningCases.java 2020-08-13 16:19:33.927000000 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8071961 + * @compile -Xlint:missing-declared-ctor -Werror --release 8 NoWarningCases.java + * @compile -Xlint:missing-declared-ctor -Werror NoWarningCases.java + */ + +public class NoWarningCases { + // No explicit constructor; use a default. + + public enum NestedEnum { + FOO, + BAR; + // No explicit constructor; use implicit one. + } +} --- /dev/null 2020-08-01 01:56:10.772000000 -0700 +++ new/test/langtools/tools/javac/warnings/DefaultCtor/NoWarningRecord.java 2020-08-13 16:19:35.119000000 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8071961 + * @compile -Xlint:missing-declared-ctor -Werror + * --enable-preview -source ${jdk.version} NoWarningRecord.java + */ + +public record NoWarningRecord(/* no components */) { + // No explicit constructor; use canonical one. +}