8015831: Add lint check for calling overridable methods from a constructor

6557145: Warn about calling abstract methods in constructors

Reviewed-by: ihse, vromero, mcimadamore
This commit is contained in:
Archie L. Cobbs 2023-03-17 22:05:50 +00:00 committed by Vicente Romero
parent b085ab9316
commit 8f5bb538ab
54 changed files with 2463 additions and 18 deletions

View file

@ -171,41 +171,41 @@ $(BUILD_DEMO_CodePointIM_JAR): $(CODEPOINT_METAINF_SERVICE_FILE)
$(eval $(call SetupBuildDemo, FileChooserDemo, \
DEMO_SUBDIR := jfc, \
DISABLED_WARNINGS := rawtypes deprecation unchecked, \
DISABLED_WARNINGS := rawtypes deprecation unchecked this-escape, \
))
$(eval $(call SetupBuildDemo, SwingSet2, \
DEMO_SUBDIR := jfc, \
EXTRA_COPY_TO_JAR := .java, \
EXTRA_MANIFEST_ATTR := SplashScreen-Image: resources/images/splash.png, \
DISABLED_WARNINGS := rawtypes deprecation unchecked static serial cast, \
DISABLED_WARNINGS := rawtypes deprecation unchecked static serial cast this-escape, \
))
$(eval $(call SetupBuildDemo, Font2DTest, \
DISABLED_WARNINGS := rawtypes deprecation unchecked serial cast, \
DISABLED_WARNINGS := rawtypes deprecation unchecked serial cast this-escape, \
DEMO_SUBDIR := jfc, \
))
$(eval $(call SetupBuildDemo, J2Ddemo, \
DEMO_SUBDIR := jfc, \
MAIN_CLASS := java2d.J2Ddemo, \
DISABLED_WARNINGS := rawtypes deprecation unchecked cast lossy-conversions, \
DISABLED_WARNINGS := rawtypes deprecation unchecked cast lossy-conversions this-escape, \
JAR_NAME := J2Ddemo, \
))
$(eval $(call SetupBuildDemo, Metalworks, \
DISABLED_WARNINGS := rawtypes unchecked, \
DISABLED_WARNINGS := rawtypes unchecked this-escape, \
DEMO_SUBDIR := jfc, \
))
$(eval $(call SetupBuildDemo, Notepad, \
DISABLED_WARNINGS := rawtypes, \
DISABLED_WARNINGS := rawtypes this-escape, \
DEMO_SUBDIR := jfc, \
))
$(eval $(call SetupBuildDemo, Stylepad, \
DEMO_SUBDIR := jfc, \
DISABLED_WARNINGS := rawtypes unchecked, \
DISABLED_WARNINGS := rawtypes unchecked this-escape, \
EXTRA_SRC_DIR := $(DEMO_SHARE_SRC)/jfc/Notepad, \
EXCLUDE_FILES := $(DEMO_SHARE_SRC)/jfc/Notepad/README.txt, \
))
@ -215,11 +215,12 @@ $(eval $(call SetupBuildDemo, SampleTree, \
))
$(eval $(call SetupBuildDemo, TableExample, \
DISABLED_WARNINGS := rawtypes unchecked deprecation, \
DISABLED_WARNINGS := rawtypes unchecked deprecation this-escape, \
DEMO_SUBDIR := jfc, \
))
$(eval $(call SetupBuildDemo, TransparentRuler, \
DISABLED_WARNINGS := this-escape, \
DEMO_SUBDIR := jfc, \
MAIN_CLASS := transparentruler.Ruler, \
))

View file

@ -53,7 +53,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JIGSAW_TOOLS, \
build/tools/jigsaw, \
COPY := .properties .html, \
BIN := $(TOOLS_CLASSES_DIR), \
DISABLED_WARNINGS := fallthrough, \
DISABLED_WARNINGS := fallthrough this-escape, \
JAVAC_FLAGS := \
--add-modules jdk.jdeps \
--add-exports java.base/jdk.internal.module=ALL-UNNAMED \

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
JAVAC_FLAGS += -XDstringConcat=inline \

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
COPY += flavormap.properties

View file

@ -23,7 +23,7 @@
# questions.
#
DISABLED_WARNINGS_java += lossy-conversions
DISABLED_WARNINGS_java += lossy-conversions this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
COPY += .gif .png .wav .txt .xml .css .pf

View file

@ -23,5 +23,7 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'

View file

@ -23,5 +23,7 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
CLEAN += jndiprovider.properties

View file

@ -0,0 +1,26 @@
#
# Copyright (c) 2023, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
DISABLED_WARNINGS_java += this-escape

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
CLEAN_FILES += $(wildcard \

View file

@ -23,5 +23,7 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'

View file

@ -0,0 +1,26 @@
#
# Copyright (c) 2023, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
DISABLED_WARNINGS_java += this-escape

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
CLEAN_FILES += $(wildcard \

View file

@ -23,5 +23,7 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:java.*,javax.*'
COPY += .dtd .xml

View file

@ -23,7 +23,7 @@
# questions.
#
DISABLED_WARNINGS_java += lossy-conversions
DISABLED_WARNINGS_java += lossy-conversions this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:$(call CommaList, javax.xml.catalog javax.xml.datatype \
javax.xml.transform javax.xml.validation javax.xml.xpath)'

View file

@ -23,4 +23,6 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += .dat

View file

@ -57,7 +57,7 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \
$(TOPDIR)/src/jdk.jdeps/share/classes, \
INCLUDES := build/tools/symbolgenerator com/sun/tools/classfile, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/create_symbols, \
DISABLED_WARNINGS := options, \
DISABLED_WARNINGS := options this-escape, \
JAVAC_FLAGS := \
$(INTERIM_LANGTOOLS_ARGS) \
$(COMPILECREATESYMBOLS_ADD_EXPORTS), \

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
DOCLINT += -Xdoclint:all/protected \
'-Xdoclint/package:-com.sun.tools.*,-jdk.internal.*,sun.tools.serialver.resources.*'
JAVAC_FLAGS += -XDstringConcat=inline

View file

@ -0,0 +1,26 @@
#
# Copyright (c) 2023, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
DISABLED_WARNINGS_java += this-escape

View file

@ -0,0 +1,26 @@
#
# Copyright (c) 2023, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
DISABLED_WARNINGS_java += this-escape

View file

@ -24,5 +24,5 @@
#
DISABLED_WARNINGS_java += rawtypes serial cast static overrides \
fallthrough
fallthrough this-escape
COPY += .gif .png .properties

View file

@ -23,4 +23,4 @@
# questions.
#
DISABLED_WARNINGS_java += missing-explicit-ctor
DISABLED_WARNINGS_java += missing-explicit-ctor this-escape

View file

@ -23,4 +23,6 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += aliasmap

View file

@ -23,4 +23,6 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += .properties .caps .txt

View file

@ -23,4 +23,6 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += .properties

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
# -parameters provides method's parameters information in class file,
# JVMCI compilers make use of that information for various sanity checks.
# Don't use Indy strings concatenation to have good JVMCI startup performance.

View file

@ -55,7 +55,7 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \
$(TOPDIR)/src/jdk.jdeps/share/classes, \
INCLUDES := build/tools/symbolgenerator com/sun/tools/classfile, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/create_symbols_javadoc, \
DISABLED_WARNINGS := options, \
DISABLED_WARNINGS := options this-escape, \
JAVAC_FLAGS := \
$(INTERIM_LANGTOOLS_ARGS) \
$(COMPILECREATESYMBOLS_ADD_EXPORTS), \

View file

@ -23,4 +23,6 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += .xml .css .svg .js .js.template .png .txt

View file

@ -23,4 +23,6 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += _options

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += .gif .png
CLEAN_FILES += $(wildcard \

View file

@ -26,6 +26,8 @@
include GensrcCommon.gmk
include GensrcProperties.gmk
DISABLED_WARNINGS_java += this-escape
$(eval $(call SetupVersionProperties, JAVAP_VERSION, \
com/sun/tools/javap/resources/version.properties))

View file

@ -25,6 +25,8 @@
COPY += .txt
DISABLED_WARNINGS_java += this-escape
CLEAN_FILES += $(wildcard \
$(TOPDIR)/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/*.properties \
$(TOPDIR)/src/jdk.jdeps/share/classes/com/sun/tools/javap/resources/*.properties)

View file

@ -25,6 +25,8 @@
include LauncherCommon.gmk
DISABLED_WARNINGS_java += this-escape
$(eval $(call SetupBuildLauncher, javap, \
MAIN_CLASS := com.sun.tools.javap.Main, \
CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
EXCLUDES += \
com/sun/tools/example/debug/bdi \
com/sun/tools/example/debug/event \

View file

@ -0,0 +1,26 @@
#
# Copyright (c) 2023, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
DISABLED_WARNINGS_java += this-escape

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += .gif .png .txt .spec .script .prerm .preinst \
.postrm .postinst .list .sh .desktop .copyright .control .plist .template \
.icns .scpt .wxs .wxl .wxi .ico .bmp .tiff .service

View file

@ -23,4 +23,6 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += .jsh .properties

View file

@ -0,0 +1,26 @@
#
# Copyright (c) 2023, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
DISABLED_WARNINGS_java += this-escape

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
COPY += _dict _th
# Exclude BreakIterator classes that are just used in compile process to generate
# data files and shouldn't go in the product

View file

@ -0,0 +1,26 @@
#
# Copyright (c) 2023, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
DISABLED_WARNINGS_java += this-escape

View file

@ -23,6 +23,8 @@
# questions.
#
DISABLED_WARNINGS_java += this-escape
# 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 \

View file

@ -51,7 +51,7 @@ $(eval $(call SetupJavaCompilation, BUILD_FAILURE_HANDLER, \
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
SRC := $(FH_BASEDIR)/src/share/classes $(FH_BASEDIR)/src/share/conf, \
BIN := $(FH_SUPPORT)/classes, \
DISABLED_WARNINGS := options serial try, \
DISABLED_WARNINGS := options serial try this-escape, \
COPY := .properties, \
CLASSPATH := $(JTREG_JAR) $(TOOLS_JAR), \
JAR := $(FH_JAR), \

View file

@ -76,7 +76,7 @@ $(eval $(call SetupJavaCompilation, BUILD_INDIFY, \
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
SRC := $(TOPDIR)/test/jdk/java/lang/invoke, \
INCLUDE_FILES := indify/Indify.java, \
DISABLED_WARNINGS := rawtypes serial options, \
DISABLED_WARNINGS := this-escape rawtypes serial options, \
BIN := $(MICROBENCHMARK_TOOLS_CLASSES), \
JAVAC_FLAGS := -XDstringConcat=inline -Xprefer:newer, \
))
@ -91,7 +91,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
SMALL_JAVA := false, \
CLASSPATH := $(MICROBENCHMARK_CLASSPATH), \
DISABLED_WARNINGS := processing rawtypes cast serial preview, \
DISABLED_WARNINGS := this-escape processing rawtypes cast serial preview, \
SRC := $(MICROBENCHMARK_SRC), \
BIN := $(MICROBENCHMARK_CLASSES), \
JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \

View file

@ -306,6 +306,11 @@ public class Lint
*/
TEXT_BLOCKS("text-blocks"),
/**
* Warn about possible 'this' escapes before subclass instance is fully initialized.
*/
THIS_ESCAPE("this-escape"),
/**
* Warn about issues relating to use of try blocks (i.e. try-with-resources)
*/

View file

@ -224,6 +224,7 @@ public class Flow {
new AssignAnalyzer().analyzeTree(env, make);
new FlowAnalyzer().analyzeTree(env, make);
new CaptureAnalyzer().analyzeTree(env, make);
new ThisEscapeAnalyzer(names, syms, types, log, lint).analyzeTree(env);
}
public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {

File diff suppressed because it is too large Load diff

View file

@ -662,6 +662,12 @@ compiler.err.not.in.profile=\
compiler.warn.forward.ref=\
reference to variable ''{0}'' before it has been initialized
compiler.warn.possible.this.escape=\
possible ''this'' escape before subclass is fully initialized
compiler.warn.possible.this.escape.location=\
previous possible ''this'' escape happens here via invocation
compiler.err.illegal.self.ref=\
self-reference in initializer

View file

@ -258,6 +258,10 @@ javac.opt.Xlint.desc.strictfp=\
javac.opt.Xlint.desc.text-blocks=\
Warn about inconsistent white space characters in text block indentation.
javac.opt.Xlint.desc.this-escape=\
Warn when a constructor invokes a method that could be overriden in an external subclass.\n\
\ Such a method would execute before the subclass constructor completes its initialization.
javac.opt.Xlint.desc.try=\
Warn about issues relating to use of try blocks (i.e. try-with-resources).

View file

@ -184,6 +184,7 @@ import javax.tools.StandardLocation;
* <tr><th scope="row">{@code strictfp} <td>unnecessary use of the {@code strictfp} modifier
* <tr><th scope="row">{@code synchronization} <td>synchronization attempts on instances of value-based classes
* <tr><th scope="row">{@code text-blocks} <td>inconsistent white space characters in text block indentation
* <tr><th scope="row">{@code this-escape} <td>superclass constructor leaking {@code this} before subclass initialized
* <tr><th scope="row">{@code try} <td>issues relating to use of {@code try} blocks
* (that is, try-with-resources)
* <tr><th scope="row">{@code unchecked} <td>unchecked operations

View file

@ -776,6 +776,9 @@ instances of value-based classes.
\f[V]text-blocks\f[R]: Warns about inconsistent white space characters
in text block indentation.
.IP \[bu] 2
\f[V]this-escape\f[R]: Warns about constructors leaking
\f[V]this\f[R] prior to subclass initialization.
.IP \[bu] 2
\f[V]try\f[R]: Warns about the issues relating to the use of try blocks
(that is, try-with-resources).
.IP \[bu] 2
@ -2213,6 +2216,48 @@ Alternately, you can remove the \f[V]static\f[R] keyword from the
declaration of the method \f[V]m1\f[R].
.RE
.TP
\f[V]this\-escape\f[R]
Warns about constructors leaking \f[V]this\f[R] prior to subclass
initialization.
For example, this class:
.RS
.IP
.nf
\f[CB]
public class MyClass {
public MyClass() {
System.out.println(this.hashCode());
}
}
\f[R]
.fi
.PP
generates the following warning:
.IP
.nf
\f[CB]
MyClass.java:3: warning: [this-escape] possible 'this' escape
before subclass is fully initialized
System.out.println(this.hashCode());
^
\f[R]
.fi
.PP
A 'this' escape warning is generated when a constructor does something
that might result in a subclass method being invoked before the
constructor returns.
In such cases the subclass method would be operating on an incompletely
initialized instance.
In the above example, a subclass of \f[V]MyClass\f[R] that overrides
\f[V]hashCode()\f[R] to incorporate its own fields would likely produce
an incorrect result when invoked as shown.
.PP
Warnings are only generated if a subclass could exist that is outside
of the current module (or package, if no module) being compiled.
So, for example, constructors in final and non-public classes do not
generate warnings.
.RE
.TP
\f[V]try\f[R]
Warns about issues relating to the use of \f[V]try\f[R] blocks,
including try-with-resources statements.

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2023, 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.possible.this.escape
// key: compiler.warn.possible.this.escape.location
// options: -Xlint:this-escape
public class ThisEscape {
public ThisEscape() {
this.method();
}
public final void method() {
this.hashCode();
}
}

View file

@ -0,0 +1,604 @@
/*
* @test /nodynamiccopyright/
* @bug 8015831
* @compile/ref=ThisEscape.out -Xlint:this-escape -XDrawDiagnostics ThisEscape.java
* @summary Verify 'this' escape detection
*/
import java.util.function.*;
public class ThisEscape {
// Verify 'this' escape detection can follow references embedded as array elements
public static class ThisEscapeArrayElement {
public ThisEscapeArrayElement() {
final Object[][] array = new Object[][] { { this } };
((ThisEscapeArrayElement)array[0][0]).mightLeak();
}
public void mightLeak() {
}
}
// Verify basic 'this' escape detection
public static class ThisEscapeBasic {
public ThisEscapeBasic() {
this.mightLeak();
}
public void mightLeak() {
}
}
// Verify 'this' escape detection can follow references through various Java code structures
public static class ThisEscapeComplex {
public ThisEscapeComplex() {
this.method1().mightLeak();
}
public void mightLeak() {
}
private ThisEscapeComplex method1() {
while (true) {
do {
for (ThisEscapeComplex x = this.method2(); new Object().hashCode() < 10; ) {
for (int y : new int[] { 123, 456 }) {
return x;
}
}
} while (true);
}
}
private ThisEscapeComplex method2() {
switch (new Object().hashCode()) {
case 1:
case 2:
case 3:
return null;
default:
return this.method3();
}
}
private ThisEscapeComplex method3() {
return switch (new Object().hashCode()) {
case 1, 2, 3 -> this.method4();
default -> null;
};
}
private ThisEscapeComplex method4() {
return ThisEscapeComplex.this.method5();
}
private ThisEscapeComplex method5() {
final ThisEscapeComplex foo = this.method6();
return foo;
}
private ThisEscapeComplex method6() {
synchronized (new Object()) {
return this.method7();
}
}
private ThisEscapeComplex method7() {
ThisEscapeComplex x = null;
ThisEscapeComplex y = this.method8();
if (new Object().hashCode() == 3)
return x;
else
return y;
}
private ThisEscapeComplex method8() {
return (ThisEscapeComplex)(Object)this.method9();
}
private ThisEscapeComplex method9() {
return new Object().hashCode() == 3 ? this : null;
}
}
// Verify pruning of 'this' escape warnings for various constructors
public static class ThisEscapeCtors {
// This constructor should NOT generate a warning because it would be a
// duplicate of the warning already generated for ThisEscapeCtors(short).
public ThisEscapeCtors(char x) {
this((short)x);
}
// This constructor should generate a warning because it invokes leaky this()
// and is accessible to subclasses.
public ThisEscapeCtors(short x) {
this();
}
// This constructor should generate a warning because it invokes leaky this()
// and is accessible to subclasses.
public ThisEscapeCtors(int x) {
this();
}
// This constructor should NOT generate a warning because it is not accessbile
// to subclasses. However, other constructors do invoke it, and that should cause
// them to generate an indirect warning.
private ThisEscapeCtors() {
this.mightLeak();
}
public void mightLeak() {
}
}
// Verify 'this' escape detection in field initializers
public static class ThisEscapeFields {
private final int field1 = this.mightLeak1();
private final int field2 = this.mightLeak2();
public int mightLeak1() {
return 123;
}
public int mightLeak2() {
return 456;
}
}
// Verify 'this' escape detection properly handles lambdas
public static class ThisEscapeLambda {
public ThisEscapeLambda() {
Runnable r = () -> {
this.mightLeak();
};
System.out.println(r);
}
public void mightLeak() {
}
}
// Verify 'this' escape detection properly handles loop convergence
public static class ThisEscapeLoop {
public ThisEscapeLoop() {
ThisEscapeLoop ref1 = this;
ThisEscapeLoop ref2 = null;
ThisEscapeLoop ref3 = null;
ThisEscapeLoop ref4 = null;
for (int i = 0; i < 100; i++) {
ref4 = ref3;
ref3 = ref2;
ref2 = ref1;
if (ref4 != null)
ref4.mightLeak();
}
}
public void mightLeak() {
}
}
// Verify 'this' escape detection handles leaks via outer 'this'
public static class ThisEscapeOuterThis {
public ThisEscapeOuterThis() {
new InnerClass();
}
public void mightLeak() {
}
public class InnerClass {
InnerClass() {
ThisEscapeOuterThis.this.mightLeak();
}
}
// No leak here because class 'Local' cannot be externally extended
public static void method1() {
class Local {
Local() {
this.wontLeak();
}
void wontLeak() {
}
}
}
}
// Verify 'this' escape detection handles leaks via passing 'this' as a parameter
public static class ThisEscapeParameter {
public ThisEscapeParameter() {
ThisEscapeParameter.method(this);
}
public static void method(Object obj) {
obj.hashCode();
}
}
// Verify 'this' escape detection properly handles leaks via recursive methods
public static class ThisEscapeRecursion {
public ThisEscapeRecursion() {
this.noLeak(0); // no leak here
this.mightLeak(); // possible leak here
}
public final void noLeak(int depth) {
if (depth < 10)
this.noLeak(depth - 1);
}
public void mightLeak() {
}
}
// Verify proper handling of 'this' escape warnings from method references
public static class ThisEscapeReference {
// Test 1 - ReferenceKind.SUPER
public static class Test1 {
public void mightLeak() {
}
}
public static class Test1b extends Test1 {
public Test1b() {
new Thread(super::mightLeak); // this is a leak
}
}
public static class Test1c extends Test1 {
public Test1c() {
new Thread(super::notify); // this is not a leak
}
}
// Test 2 - ReferenceKind.BOUND
public static class Test2 {
public Test2() {
new Thread(this::mightLeak); // this is a leak
}
public Test2(int x) {
final Test2 foo = new Test2();
new Thread(foo::mightLeak); // this is not a leak
}
public Test2(char x) {
new Thread(this::noLeak); // this is not a leak
}
public void mightLeak() {
}
private void noLeak() {
}
}
// Test 3 - ReferenceKind.IMPLICIT_INNER
public static class Test3 {
public Test3() {
new Thread(Inner1::new); // this is a leak
}
public Test3(int x) {
new Thread(Inner2::new); // this is not a leak
}
public void mightLeak() {
}
public class Inner1 {
public Inner1() {
Test3.this.mightLeak();
}
}
public class Inner2 {
public Inner2() {
new Test3().mightLeak();
}
}
}
// Test 4 - ReferenceKind.UNBOUND, STATIC, TOPLEVEL, ARRAY_CTOR
public static class Test4 {
// ReferenceKind.UNBOUND
public Test4() {
Test4.bar(Test4::sameHashCode);
}
// ReferenceKind.STATIC
public Test4(int x) {
new Thread(Test4::noLeak); // this is not a leak
}
// ReferenceKind.ARRAY_CTOR
public Test4(char x) {
Test4.foo(String[]::new); // this is not a leak
}
// ReferenceKind.TOPLEVEL
public Test4(short x) {
Test4.foo(Test4::new); // this is not a leak
}
public static void noLeak() {
}
public static void foo(IntFunction<?> x) {
x.hashCode();
}
public static void bar(BiPredicate<Test4, Object> x) {
x.hashCode();
}
public boolean sameHashCode(Object obj) {
return obj.hashCode() == this.hashCode();
}
}
}
// Verify 'this' escape detection properly handles leaks via method return values
public static class ThisEscapeReturnValue {
public ThisEscapeReturnValue() {
final Object rval = ThisEscapeReturnValue.method(this);
((ThisEscapeReturnValue)rval).mightLeak();
}
public static Object method(Object obj) {
return obj;
}
public void mightLeak() {
}
}
// Verify 'this' escape detection from a thrown 'this'
public static class ThisEscapeThrown extends RuntimeException {
public ThisEscapeThrown(Object obj) {
if (obj == null)
throw this;
}
}
// Verify proper 'this' escape interpretation of unqualified non-static method invocations
public static class ThisEscapeUnqualified {
// This class has a leak
public static class Example1 {
public Example1() {
new Inner();
}
public final class Inner {
public Inner() {
mightLeak(); // refers to Example1.mightLeak()
}
}
public void mightLeak() {
}
}
// This class does NOT have a leak
public static class Example2 {
public Example2() {
new Inner();
}
public final class Inner {
public Inner() {
mightLeak(); // refers to Inner.mightLeak()
}
public void mightLeak() {
}
}
public void mightLeak() {
}
}
}
// Verify 'this' escape detection handles leaks via switch expression yields
public static class ThisEscapeYield {
public ThisEscapeYield(int x) {
ThisEscapeYield y = switch (x) {
case 3:
if (x > 17)
yield this;
else
yield null;
default:
yield null;
};
if (y != null)
y.mightLeak();
}
public void mightLeak() {
}
}
// Verify 'this' escape warnings can be properly suppressed on constructors
public static class ThisEscapeSuppressCtor {
private final int x = this.mightLeak();
@SuppressWarnings("this-escape")
public ThisEscapeSuppressCtor() {
this.mightLeak();
}
public int mightLeak() {
return 0;
}
}
// Verify 'this' escape warnings can be properly suppressed on fields
public static class ThisEscapeSuppressField {
@SuppressWarnings("this-escape")
private final int x = this.mightLeak();
public ThisEscapeSuppressField() {
this.mightLeak();
}
public int mightLeak() {
return 0;
}
}
// Verify 'this' escape warnings can be properly suppressed on classes
public static class ThisEscapeSuppressClass {
@SuppressWarnings("this-escape")
private final int x = this.mightLeak();
@SuppressWarnings("this-escape")
public ThisEscapeSuppressClass() {
this.mightLeak();
}
public int mightLeak() {
return 0;
}
}
// Verify 'this' escape detection doesn't generate certain false positives
public static class ThisEscapeNoEscapes {
public ThisEscapeNoEscapes() {
this.noLeak1(); // invoked method is private
this.noLeak2(); // invoked method is final
ThisEscapeNoEscapes.noLeak3(); // invoked method is static
this.noLeak4(this); // parameter is 'this' but it's not leaked
this.noLeak5(new ThisEscapeNoEscapes(0)); // parameter is not 'this', so no leak
this.noLeak6(null, this, null); // method leaks 1st and 3rd parameters only
this.noLeak7(); // method does complicated stuff but doesn't leak
Runnable r1 = () -> { // lambda does not leak 'this'
if (System.out == System.err)
throw new RuntimeException();
};
System.out.println(r1); // lambda does not leak 'this'
Runnable r2 = () -> { // lambda leaks 'this' but is never used
this.mightLeak1();
};
Runnable r3 = this::mightLeak1; // reference leaks 'this' but is never used
}
public ThisEscapeNoEscapes(int x) {
}
public void mightLeak1() {
}
private void noLeak1() {
}
public final void noLeak2() {
}
public static void noLeak3() {
}
public static void noLeak4(ThisEscapeNoEscapes param) {
param.noLeak1();
param.noLeak2();
}
public final void noLeak5(ThisEscapeNoEscapes param) {
param.mightLeak1();
}
public final void noLeak6(ThisEscapeNoEscapes param1,
ThisEscapeNoEscapes param2, ThisEscapeNoEscapes param3) {
if (param1 != null)
param1.mightLeak1();
if (param2 != null)
param2.noLeak2();
if (param3 != null)
param3.mightLeak1();
}
public final void noLeak7() {
((ThisEscapeNoEscapes)(Object)this).noLeak2();
final ThisEscapeNoEscapes obj1 = switch (new Object().hashCode()) {
case 1, 2, 3 -> null;
default -> new ThisEscapeNoEscapes(0);
};
obj1.mightLeak1();
}
// PrivateClass
private static class PrivateClass {
PrivateClass() {
this.cantLeak(); // method is inside a private class
}
public void cantLeak() {
}
}
// FinalClass
public static final class FinalClass extends ThisEscapeNoEscapes {
public FinalClass() {
this.mightLeak1(); // class and therefore method is final
}
}
public static void main(String[] args) {
new ThisEscapeNoEscapes();
}
}
// Verify 'this' escape detection doesn't warn for sealed classes with local permits
public static sealed class ThisEscapeSealed permits ThisEscapeSealed.Sub1, ThisEscapeSealed.Sub2 {
public ThisEscapeSealed() {
this.mightLeak();
}
public void mightLeak() {
}
public static final class Sub1 extends ThisEscapeSealed {
}
public static final class Sub2 extends ThisEscapeSealed {
}
}
}

View file

@ -0,0 +1,26 @@
ThisEscape.java:17:60: compiler.warn.possible.this.escape
ThisEscape.java:28:27: compiler.warn.possible.this.escape
ThisEscape.java:39:37: compiler.warn.possible.this.escape
ThisEscape.java:120:17: compiler.warn.possible.this.escape
ThisEscape.java:133:27: compiler.warn.possible.this.escape.location
ThisEscape.java:126:17: compiler.warn.possible.this.escape
ThisEscape.java:133:27: compiler.warn.possible.this.escape.location
ThisEscape.java:143:51: compiler.warn.possible.this.escape
ThisEscape.java:145:51: compiler.warn.possible.this.escape
ThisEscape.java:163:32: compiler.warn.possible.this.escape
ThisEscape.java:183:35: compiler.warn.possible.this.escape
ThisEscape.java:195:13: compiler.warn.possible.this.escape
ThisEscape.java:204:51: compiler.warn.possible.this.escape.location
ThisEscape.java:224:39: compiler.warn.possible.this.escape
ThisEscape.java:228:25: compiler.warn.possible.this.escape.location
ThisEscape.java:237:27: compiler.warn.possible.this.escape
ThisEscape.java:261:28: compiler.warn.possible.this.escape
ThisEscape.java:276:28: compiler.warn.possible.this.escape
ThisEscape.java:300:28: compiler.warn.possible.this.escape
ThisEscape.java:369:52: compiler.warn.possible.this.escape
ThisEscape.java:385:17: compiler.warn.possible.this.escape
ThisEscape.java:396:17: compiler.warn.possible.this.escape
ThisEscape.java:401:30: compiler.warn.possible.this.escape.location
ThisEscape.java:444:28: compiler.warn.possible.this.escape
ThisEscape.java:473:27: compiler.warn.possible.this.escape
25 warnings