Merge
This commit is contained in:
commit
eed5d34c26
1
.hgtags
1
.hgtags
@ -449,3 +449,4 @@ a85884d55ce32799f5c7382b7ea4839052b362a2 jdk-10+21
|
||||
e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22
|
||||
22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23
|
||||
3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24
|
||||
8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25
|
||||
|
@ -28,8 +28,8 @@
|
||||
mydir="$(dirname "${BASH_SOURCE[0]}")"
|
||||
myname="$(basename "${BASH_SOURCE[0]}")"
|
||||
|
||||
installed_jib_script=${mydir}/../../.jib/jib
|
||||
install_data=${mydir}/../../.jib/.data
|
||||
installed_jib_script=${mydir}/../.jib/jib
|
||||
install_data=${mydir}/../.jib/.data
|
||||
|
||||
setup_url() {
|
||||
if [ -f ~/.config/jib/jib.conf ]; then
|
||||
@ -42,7 +42,7 @@ setup_url() {
|
||||
jib_revision="2.0-SNAPSHOT"
|
||||
jib_ext="jib.sh.gz"
|
||||
|
||||
closed_script="${mydir}/../../../closed/conf/jib-install.conf"
|
||||
closed_script="${mydir}/../../closed/make/conf/jib-install.conf"
|
||||
if [ -f "${closed_script}" ]; then
|
||||
source "${closed_script}"
|
||||
fi
|
||||
|
@ -127,7 +127,7 @@ scripting language.</span></p>
|
||||
<hr>
|
||||
<span><a name="package" id="package"></a></span>
|
||||
<h2><span>Scripting Package</span></h2>
|
||||
<p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/6/docs/api/javax/script/package-summary.html">javax.script</a></code>
|
||||
<p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/9/docs/api/javax/script/package-summary.html">javax.script</a></code>
|
||||
package. This is a relatively small, simple API. The starting point
|
||||
of the scripting API is the <code>ScriptEngineManager</code> class.
|
||||
A ScriptEngineManager object can discover script engines through
|
||||
|
@ -41,7 +41,7 @@ JDK_CLASSES := $(call PathList, $(strip $(addprefix $(JDK_OUTPUTDIR)/modules/, \
|
||||
$(eval $(call SetupJavaCompiler, GENERATE_NEWBYTECODE_DEBUG, \
|
||||
JVM := $(JAVA_JAVAC), \
|
||||
JAVAC := $(NEW_JAVAC), \
|
||||
FLAGS := -g -source 9 -target 9 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
|
||||
FLAGS := -g -source 10 -target 10 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
|
||||
--system none --module-source-path $(call GetModuleSrcPath), \
|
||||
SERVER_DIR := $(SJAVAC_SERVER_DIR), \
|
||||
SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
|
||||
|
@ -36,7 +36,7 @@ ifeq ($(HAS_SPEC),)
|
||||
|
||||
# Include the corresponding closed file, if present.
|
||||
# Normal hook mechanism cannot be used since we have no SPEC.
|
||||
-include $(topdir)/closed/make/InitSupport.gmk
|
||||
-include $(topdir)/../closed/make/InitSupport.gmk
|
||||
|
||||
##############################################################################
|
||||
# Helper functions for the initial part of Init.gmk, before the spec file is
|
||||
|
@ -1311,6 +1311,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER],
|
||||
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDK}"
|
||||
|
||||
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
|
||||
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
|
||||
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
$2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
|
||||
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
|
||||
@ -1388,6 +1389,7 @@ $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${$2JAVA_BASE_LDFLAGS}"
|
||||
AC_SUBST($2JDKEXE_LIBS)
|
||||
AC_SUBST($2LDFLAGS_CXX_JDK)
|
||||
AC_SUBST($2LDFLAGS_HASH_STYLE)
|
||||
AC_SUBST($2LDFLAGS_NO_EXEC_STACK)
|
||||
|
||||
AC_SUBST($2JVM_CFLAGS)
|
||||
AC_SUBST($2JVM_LDFLAGS)
|
||||
|
@ -723,6 +723,7 @@ OPENJDK_BUILD_JVM_LIBS
|
||||
OPENJDK_BUILD_JVM_ASFLAGS
|
||||
OPENJDK_BUILD_JVM_LDFLAGS
|
||||
OPENJDK_BUILD_JVM_CFLAGS
|
||||
OPENJDK_BUILD_LDFLAGS_NO_EXEC_STACK
|
||||
OPENJDK_BUILD_LDFLAGS_HASH_STYLE
|
||||
OPENJDK_BUILD_LDFLAGS_CXX_JDK
|
||||
OPENJDK_BUILD_JDKEXE_LIBS
|
||||
@ -738,6 +739,7 @@ JVM_LIBS
|
||||
JVM_ASFLAGS
|
||||
JVM_LDFLAGS
|
||||
JVM_CFLAGS
|
||||
LDFLAGS_NO_EXEC_STACK
|
||||
LDFLAGS_HASH_STYLE
|
||||
LDFLAGS_CXX_JDK
|
||||
JDKEXE_LIBS
|
||||
@ -5115,7 +5117,7 @@ VS_SDK_PLATFORM_NAME_2013=
|
||||
#CUSTOM_AUTOCONF_INCLUDE
|
||||
|
||||
# Do not change or remove the following line, it is needed for consistency checks:
|
||||
DATE_WHEN_GENERATED=1506333008
|
||||
DATE_WHEN_GENERATED=1506397140
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -52024,6 +52026,7 @@ fi
|
||||
LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
|
||||
|
||||
LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
|
||||
LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
|
||||
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
|
||||
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
|
||||
@ -52109,6 +52112,7 @@ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${JAVA_BASE_LDFLAGS}"
|
||||
|
||||
|
||||
|
||||
|
||||
# Special extras...
|
||||
if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
|
||||
if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then
|
||||
@ -52903,6 +52907,7 @@ fi
|
||||
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDK}"
|
||||
|
||||
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
|
||||
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
|
||||
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
|
||||
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
|
||||
@ -52988,6 +52993,7 @@ OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${OPENJDK_BUILD_JA
|
||||
|
||||
|
||||
|
||||
|
||||
# Tests are only ever compiled for TARGET
|
||||
# Flags for compiling test libraries
|
||||
CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
|
||||
|
@ -387,6 +387,7 @@ CFLAGS_JDKEXE:=@CFLAGS_JDKEXE@
|
||||
CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@
|
||||
|
||||
LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@
|
||||
LDFLAGS_NO_EXEC_STACK := @LDFLAGS_NO_EXEC_STACK@
|
||||
|
||||
JVM_CFLAGS := @JVM_CFLAGS@
|
||||
JVM_CFLAGS_SYMBOLS := @JVM_CFLAGS_SYMBOLS@
|
||||
|
@ -58,7 +58,6 @@ BOOT_MODULES += \
|
||||
java.rmi \
|
||||
java.security.sasl \
|
||||
java.xml \
|
||||
jdk.httpserver \
|
||||
jdk.internal.vm.ci \
|
||||
jdk.management \
|
||||
jdk.management.agent \
|
||||
@ -112,6 +111,7 @@ PLATFORM_MODULES += \
|
||||
jdk.crypto.cryptoki \
|
||||
jdk.crypto.ec \
|
||||
jdk.dynalink \
|
||||
jdk.httpserver \
|
||||
jdk.incubator.httpclient \
|
||||
jdk.internal.vm.compiler.management \
|
||||
jdk.jsobject \
|
||||
|
@ -900,6 +900,45 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
}
|
||||
},
|
||||
|
||||
"windows-x64-open": {
|
||||
artifacts: {
|
||||
jdk: {
|
||||
local: "bundles/\\(jdk.*bin.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x64/jdk-" + data.version
|
||||
+ "_windows-x64_bin.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x64/\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre: {
|
||||
local: "bundles/\\(jre.*bin.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/windows-x64/\\1"
|
||||
},
|
||||
test: {
|
||||
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x64/jdk-" + data.version
|
||||
+ "_windows-x64_bin-tests.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x64/\\1"
|
||||
]
|
||||
},
|
||||
jdk_symbols: {
|
||||
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/windows-x64/jdk-" + data.version
|
||||
+ "_windows-x64_bin-symbols.tar.gz",
|
||||
"bundles/openjdk/GPL/windows-x64/\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre_symbols: {
|
||||
local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/windows-x64/\\1",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"linux-x86-open-debug": {
|
||||
artifacts: {
|
||||
jdk: {
|
||||
@ -929,9 +968,10 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]);
|
||||
profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]);
|
||||
profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]);
|
||||
profiles["windows-x64-ri"] = clone(profiles["windows-x64-open"]);
|
||||
|
||||
// Generate artifacts for ri profiles
|
||||
[ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri" ]
|
||||
[ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri", "windows-x64-ri" ]
|
||||
.forEach(function (name) {
|
||||
// Rewrite all remote dirs to "bundles/openjdk/BCL/..."
|
||||
for (artifactName in profiles[name].artifacts) {
|
||||
@ -947,6 +987,11 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
configure_args: "--with-freetype-license="
|
||||
+ input.get("freetype", "install_path")
|
||||
+ "/freetype-2.7.1-v120-x86/freetype.md"
|
||||
},
|
||||
"windows-x64-ri": {
|
||||
configure_args: "--with-freetype-license="
|
||||
+ input.get("freetype", "install_path")
|
||||
+ "/freetype-2.7.1-v120-x64/freetype.md"
|
||||
}
|
||||
};
|
||||
profiles = concatObjects(profiles, profilesRiFreetype);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2013, 2017, 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
|
||||
@ -36,7 +36,7 @@ ifneq ($(OPENJDK_TARGET_OS), windows)
|
||||
ifeq ($(STATIC_BUILD), false)
|
||||
ifeq ($(OPENJDK_TARGET_OS), linux)
|
||||
LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS)
|
||||
LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) $(EXTRA_CFLAGS)
|
||||
LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) ${LDFLAGS_NO_EXEC_STACK} $(EXTRA_CFLAGS)
|
||||
LIBJSIG_LIBS := $(LIBDL)
|
||||
|
||||
# NOTE: The old build compiled this library without -soname.
|
||||
|
@ -57,8 +57,8 @@ public class TransitiveDependencies {
|
||||
}
|
||||
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
List<String> options = Arrays.asList("-source", "9",
|
||||
"-target", "9",
|
||||
List<String> options = Arrays.asList("-source", "10",
|
||||
"-target", "10",
|
||||
"-proc:only",
|
||||
"--system", "none",
|
||||
"--module-source-path", args[0],
|
||||
|
@ -174,8 +174,6 @@
|
||||
<target name="compile" depends="prepare" description="Compiles nashorn">
|
||||
<javac srcdir="${dynalink.module.src.dir}"
|
||||
destdir="${dynalink.module.classes.dir}"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false" fork="true">
|
||||
@ -190,8 +188,6 @@
|
||||
</delete>
|
||||
<javac srcdir="${nashorn.module.src.dir}"
|
||||
destdir="${nashorn.module.classes.dir}"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false" fork="true">
|
||||
@ -207,8 +203,6 @@
|
||||
</delete>
|
||||
<javac srcdir="${nashorn.shell.module.src.dir}"
|
||||
destdir="${nashorn.shell.module.classes.dir}"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false" fork="true">
|
||||
@ -342,8 +336,6 @@
|
||||
<javac srcdir="${test.src.dir}"
|
||||
destdir="${build.test.classes.dir}"
|
||||
classpath="${javac.test.classpath}"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false" fork="true">
|
||||
@ -351,7 +343,7 @@
|
||||
<compilerarg value="-Xlint:unchecked"/>
|
||||
<compilerarg value="-Xlint:deprecation"/>
|
||||
<compilerarg value="-Xdiags:verbose"/>
|
||||
<compilerarg line="${test.module.imports}"/>
|
||||
<compilerarg line="${test.module.imports.compile.time}"/>
|
||||
</javac>
|
||||
|
||||
<copy todir="${build.test.classes.dir}/META-INF/services">
|
||||
|
@ -24,8 +24,6 @@ application.title=nasgen
|
||||
|
||||
# source and target levels
|
||||
build.compiler=modern
|
||||
javac.source=1.7
|
||||
javac.target=1.7
|
||||
|
||||
# This directory is removed when the project is cleaned:
|
||||
nasgen.build.dir=../../../../build/nashorn/nasgen
|
||||
|
@ -24,8 +24,6 @@ application.title=nashorntask
|
||||
|
||||
# source and target levels
|
||||
build.compiler=modern
|
||||
javac.source=1.8
|
||||
javac.target=1.8
|
||||
|
||||
# This directory is removed when the project is cleaned:
|
||||
nashorntask.build.dir=../../../../build/nashorn/nashorntask
|
||||
|
@ -32,8 +32,6 @@ jdk.jline.src.dir=src/jdk.internal.le/share/classes
|
||||
|
||||
# source and target levels
|
||||
build.compiler=modern
|
||||
javac.source=1.9
|
||||
javac.target=1.9
|
||||
|
||||
javadoc.option=\
|
||||
-tag "implSpec:a:Implementation Requirements:" \
|
||||
@ -146,7 +144,7 @@ javac.test.classpath=\
|
||||
${file.reference.bsh.jar}${path.separator}\
|
||||
${file.reference.snakeyaml.jar}
|
||||
|
||||
test.module.imports=\
|
||||
test.module.imports.compile.time=\
|
||||
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.ir=ALL-UNNAMED \
|
||||
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.codegen=ALL-UNNAMED \
|
||||
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.parser=ALL-UNNAMED \
|
||||
@ -159,7 +157,10 @@ test.module.imports=\
|
||||
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp=ALL-UNNAMED \
|
||||
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp.joni=ALL-UNNAMED \
|
||||
--add-exports jdk.scripting.nashorn/jdk.nashorn.tools=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
|
||||
--add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
|
||||
|
||||
test.module.imports.runtime=\
|
||||
${test.module.imports.compile.time} \
|
||||
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime=ALL-UNNAMED \
|
||||
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv=ALL-UNNAMED
|
||||
|
||||
@ -359,7 +360,7 @@ run.test.user.country=TR
|
||||
|
||||
run.test.jvmargs.common=\
|
||||
-server \
|
||||
${test.module.imports} \
|
||||
${test.module.imports.runtime} \
|
||||
${run.test.jvmargs.external} \
|
||||
--add-modules jdk.scripting.nashorn.shell \
|
||||
${nashorn.override.option} \
|
||||
|
@ -73,6 +73,9 @@
|
||||
#include "utilities/nativeCallStack.hpp"
|
||||
#endif // INCLUDE_NMT
|
||||
|
||||
#ifdef LINUX
|
||||
#include "utilities/elfFile.hpp"
|
||||
#endif
|
||||
|
||||
#define SIZE_T_MAX_VALUE ((size_t) -1)
|
||||
|
||||
@ -1823,6 +1826,20 @@ WB_ENTRY(void, WB_RemoveCompilerDirective(JNIEnv* env, jobject o, jint count))
|
||||
DirectivesStack::pop(count);
|
||||
WB_END
|
||||
|
||||
// Checks that the library libfile has the noexecstack bit set.
|
||||
WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstring libfile))
|
||||
jboolean ret = false;
|
||||
#ifdef LINUX
|
||||
// Can't be in VM when we call JNI.
|
||||
ThreadToNativeFromVM ttnfv(thread);
|
||||
const char* lf = env->GetStringUTFChars(libfile, NULL);
|
||||
CHECK_JNI_EXCEPTION_(env, 0);
|
||||
ret = (jboolean) ElfFile::specifies_noexecstack(lf);
|
||||
env->ReleaseStringUTFChars(libfile, lf);
|
||||
#endif
|
||||
return ret;
|
||||
WB_END
|
||||
|
||||
#define CC (char*)
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
@ -2027,6 +2044,8 @@ static JNINativeMethod methods[] = {
|
||||
(void*)&WB_GetConcurrentGCPhases},
|
||||
{CC"requestConcurrentGCPhase0", CC"(Ljava/lang/String;)Z",
|
||||
(void*)&WB_RequestConcurrentGCPhase},
|
||||
{CC"checkLibSpecifiesNoexecstack", CC"(Ljava/lang/String;)Z",
|
||||
(void*)&WB_CheckLibSpecifiesNoexecstack},
|
||||
};
|
||||
|
||||
#undef CC
|
||||
|
@ -2160,10 +2160,12 @@ public abstract class ClassLoader {
|
||||
* if a package of the given {@code name} is already
|
||||
* defined by this class loader
|
||||
*
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*
|
||||
* @jvms 5.3 Run-time package
|
||||
* @see <a href="{@docRoot}/../specs/jar/jar.html#sealing">
|
||||
* The JAR File Specification: Package Sealing</a>
|
||||
*/
|
||||
@ -2186,17 +2188,19 @@ public abstract class ClassLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Package} of the given <a href="#name">name</a> that has been
|
||||
* defined by this class loader.
|
||||
* Returns a {@code Package} of the given <a href="#name">name</a> that
|
||||
* has been defined by this class loader.
|
||||
*
|
||||
* @param name The <a href="#name">package name</a>
|
||||
*
|
||||
* @return The {@code Package} of the given name defined by this class loader,
|
||||
* or {@code null} if not found
|
||||
* @return The {@code Package} of the given name that has been defined
|
||||
* by this class loader, or {@code null} if not found
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* if {@code name} is {@code null}.
|
||||
*
|
||||
* @jvms 5.3 Run-time package
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@ -2211,14 +2215,18 @@ public abstract class ClassLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the {@code Package}s defined by this class loader.
|
||||
* The returned array has no duplicated {@code Package}s of the same name.
|
||||
* Returns all of the {@code Package}s that have been defined by
|
||||
* this class loader. The returned array has no duplicated {@code Package}s
|
||||
* of the same name.
|
||||
*
|
||||
* @apiNote This method returns an array rather than a {@code Set} or {@code Stream}
|
||||
* for consistency with the existing {@link #getPackages} method.
|
||||
*
|
||||
* @return The array of {@code Package} objects defined by this class loader;
|
||||
* or an zero length array if no package has been defined by this class loader.
|
||||
* @return The array of {@code Package} objects that have been defined by
|
||||
* this class loader; or an zero length array if no package has been
|
||||
* defined by this class loader.
|
||||
*
|
||||
* @jvms 5.3 Run-time package
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
@ -2244,7 +2252,7 @@ public abstract class ClassLoader {
|
||||
* @param name
|
||||
* The <a href="#name">package name</a>
|
||||
*
|
||||
* @return The {@code Package} corresponding to the given name defined by
|
||||
* @return The {@code Package} of the given name that has been defined by
|
||||
* this class loader or its ancestors, or {@code null} if not found.
|
||||
*
|
||||
* @throws NullPointerException
|
||||
@ -2263,6 +2271,8 @@ public abstract class ClassLoader {
|
||||
* {@link ClassLoader#getDefinedPackage} method which returns
|
||||
* a {@code Package} for the specified class loader.
|
||||
*
|
||||
* @see ClassLoader#getDefinedPackage(String)
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
@ -2281,10 +2291,10 @@ public abstract class ClassLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the {@code Package}s defined by this class loader
|
||||
* and its ancestors. The returned array may contain more than one
|
||||
* {@code Package} object of the same package name, each defined by
|
||||
* a different class loader in the class loader hierarchy.
|
||||
* Returns all of the {@code Package}s that have been defined by
|
||||
* this class loader and its ancestors. The returned array may contain
|
||||
* more than one {@code Package} object of the same package name, each
|
||||
* defined by a different class loader in the class loader hierarchy.
|
||||
*
|
||||
* @apiNote The {@link #getPlatformClassLoader() platform class loader}
|
||||
* may delegate to the application class loader. In other words,
|
||||
@ -2294,8 +2304,10 @@ public abstract class ClassLoader {
|
||||
* when invoked on the platform class loader, this method will not
|
||||
* return any packages defined to the application class loader.
|
||||
*
|
||||
* @return The array of {@code Package} objects defined by this
|
||||
* class loader and its ancestors
|
||||
* @return The array of {@code Package} objects that have been defined by
|
||||
* this class loader and its ancestors
|
||||
*
|
||||
* @see ClassLoader#getDefinedPackages()
|
||||
*
|
||||
* @since 1.2
|
||||
* @revised 9
|
||||
|
@ -29,6 +29,7 @@ import jdk.internal.misc.SharedSecrets;
|
||||
|
||||
import static java.lang.StackWalker.Option.*;
|
||||
import java.lang.StackWalker.StackFrame;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
class StackFrameInfo implements StackFrame {
|
||||
private final static JavaLangInvokeAccess JLIA =
|
||||
@ -78,6 +79,17 @@ class StackFrameInfo implements StackFrame {
|
||||
return JLIA.getName(memberName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodType getMethodType() {
|
||||
walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE);
|
||||
return JLIA.getMethodType(memberName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptor() {
|
||||
return JLIA.getMethodDescriptor(memberName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getByteCodeIndex() {
|
||||
// bci not available for native methods
|
||||
|
@ -26,10 +26,12 @@ package java.lang;
|
||||
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -96,7 +98,7 @@ public final class StackWalker {
|
||||
* @since 9
|
||||
* @jvms 2.6
|
||||
*/
|
||||
public static interface StackFrame {
|
||||
public interface StackFrame {
|
||||
/**
|
||||
* Gets the <a href="ClassLoader.html#name">binary name</a>
|
||||
* of the declaring class of the method represented by this stack frame.
|
||||
@ -127,6 +129,47 @@ public final class StackWalker {
|
||||
*/
|
||||
public Class<?> getDeclaringClass();
|
||||
|
||||
/**
|
||||
* Returns the {@link MethodType} representing the parameter types and
|
||||
* the return type for the method represented by this stack frame.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation throws {@code UnsupportedOperationException}.
|
||||
*
|
||||
* @return the {@code MethodType} for this stack frame
|
||||
*
|
||||
* @throws UnsupportedOperationException if this {@code StackWalker}
|
||||
* is not configured with {@link Option#RETAIN_CLASS_REFERENCE
|
||||
* Option.RETAIN_CLASS_REFERENCE}.
|
||||
*
|
||||
* @since 10
|
||||
*/
|
||||
public default MethodType getMethodType() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <i>descriptor</i> of the method represented by
|
||||
* this stack frame as defined by
|
||||
* <cite>The Java Virtual Machine Specification</cite>.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation throws {@code UnsupportedOperationException}.
|
||||
*
|
||||
* @return the descriptor of the method represented by
|
||||
* this stack frame
|
||||
*
|
||||
* @see MethodType#fromMethodDescriptorString(String, ClassLoader)
|
||||
* @see MethodType#toMethodDescriptorString()
|
||||
* @jvms 4.3.3 Method Descriptor
|
||||
*
|
||||
* @since 10
|
||||
*/
|
||||
public default String getDescriptor() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index to the code array of the {@code Code} attribute
|
||||
* containing the execution point represented by this stack frame.
|
||||
|
@ -28,6 +28,7 @@ package java.lang.invoke;
|
||||
import java.util.Arrays;
|
||||
import static java.lang.invoke.LambdaForm.*;
|
||||
import static java.lang.invoke.LambdaForm.Kind.*;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
|
||||
/**
|
||||
@ -158,8 +159,11 @@ abstract class DelegatingMethodHandle extends MethodHandle {
|
||||
static final NamedFunction NF_getTarget;
|
||||
static {
|
||||
try {
|
||||
NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
|
||||
.getDeclaredMethod("getTarget"));
|
||||
MemberName member = new MemberName(DelegatingMethodHandle.class, "getTarget",
|
||||
MethodType.methodType(MethodHandle.class), REF_invokeVirtual);
|
||||
NF_getTarget = new NamedFunction(
|
||||
MemberName.getFactory()
|
||||
.resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class));
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
|
@ -753,42 +753,38 @@ class DirectMethodHandle extends MethodHandle {
|
||||
return nf;
|
||||
}
|
||||
|
||||
private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
|
||||
|
||||
private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
|
||||
|
||||
private static NamedFunction createFunction(byte func) {
|
||||
try {
|
||||
switch (func) {
|
||||
case NF_internalMemberName:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("internalMemberName", Object.class));
|
||||
return getNamedFunction("internalMemberName", OBJ_OBJ_TYPE);
|
||||
case NF_internalMemberNameEnsureInit:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
|
||||
return getNamedFunction("internalMemberNameEnsureInit", OBJ_OBJ_TYPE);
|
||||
case NF_ensureInitialized:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("ensureInitialized", Object.class));
|
||||
return getNamedFunction("ensureInitialized", MethodType.methodType(void.class, Object.class));
|
||||
case NF_fieldOffset:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("fieldOffset", Object.class));
|
||||
return getNamedFunction("fieldOffset", LONG_OBJ_TYPE);
|
||||
case NF_checkBase:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("checkBase", Object.class));
|
||||
return getNamedFunction("checkBase", OBJ_OBJ_TYPE);
|
||||
case NF_staticBase:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("staticBase", Object.class));
|
||||
return getNamedFunction("staticBase", OBJ_OBJ_TYPE);
|
||||
case NF_staticOffset:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("staticOffset", Object.class));
|
||||
return getNamedFunction("staticOffset", LONG_OBJ_TYPE);
|
||||
case NF_checkCast:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("checkCast", Object.class, Object.class));
|
||||
return getNamedFunction("checkCast", MethodType.methodType(Object.class, Object.class, Object.class));
|
||||
case NF_allocateInstance:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("allocateInstance", Object.class));
|
||||
return getNamedFunction("allocateInstance", OBJ_OBJ_TYPE);
|
||||
case NF_constructorMethod:
|
||||
return new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("constructorMethod", Object.class));
|
||||
return getNamedFunction("constructorMethod", OBJ_OBJ_TYPE);
|
||||
case NF_UNSAFE:
|
||||
return new NamedFunction(new MemberName(MethodHandleStatics.class
|
||||
.getDeclaredField("UNSAFE")));
|
||||
MemberName member = new MemberName(MethodHandleStatics.class, "UNSAFE", Unsafe.class, REF_getField);
|
||||
return new NamedFunction(
|
||||
MemberName.getFactory()
|
||||
.resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class));
|
||||
default:
|
||||
throw newInternalError("Unknown function: " + func);
|
||||
}
|
||||
@ -797,6 +793,15 @@ class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
}
|
||||
|
||||
private static NamedFunction getNamedFunction(String name, MethodType type)
|
||||
throws ReflectiveOperationException
|
||||
{
|
||||
MemberName member = new MemberName(DirectMethodHandle.class, name, type, REF_invokeStatic);
|
||||
return new NamedFunction(
|
||||
MemberName.getFactory()
|
||||
.resolveOrFail(REF_invokeStatic, member, DirectMethodHandle.class, NoSuchMethodException.class));
|
||||
}
|
||||
|
||||
static {
|
||||
// The Holder class will contain pre-generated DirectMethodHandles resolved
|
||||
// speculatively using MemberName.getFactory().resolveOrNull. However, that
|
||||
|
@ -611,23 +611,17 @@ class Invokers {
|
||||
try {
|
||||
switch (func) {
|
||||
case NF_checkExactType:
|
||||
return new NamedFunction(Invokers.class
|
||||
.getDeclaredMethod("checkExactType", MethodHandle.class, MethodType.class));
|
||||
return getNamedFunction("checkExactType", MethodType.methodType(void.class, MethodHandle.class, MethodType.class));
|
||||
case NF_checkGenericType:
|
||||
return new NamedFunction(Invokers.class
|
||||
.getDeclaredMethod("checkGenericType", MethodHandle.class, MethodType.class));
|
||||
return getNamedFunction("checkGenericType", MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
|
||||
case NF_getCallSiteTarget:
|
||||
return new NamedFunction(Invokers.class
|
||||
.getDeclaredMethod("getCallSiteTarget", CallSite.class));
|
||||
return getNamedFunction("getCallSiteTarget", MethodType.methodType(MethodHandle.class, CallSite.class));
|
||||
case NF_checkCustomized:
|
||||
return new NamedFunction(Invokers.class
|
||||
.getDeclaredMethod("checkCustomized", MethodHandle.class));
|
||||
return getNamedFunction("checkCustomized", MethodType.methodType(void.class, MethodHandle.class));
|
||||
case NF_checkVarHandleGenericType:
|
||||
return new NamedFunction(Invokers.class
|
||||
.getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class));
|
||||
return getNamedFunction("checkVarHandleGenericType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
|
||||
case NF_checkVarHandleExactType:
|
||||
return new NamedFunction(Invokers.class
|
||||
.getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class));
|
||||
return getNamedFunction("checkVarHandleExactType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
|
||||
default:
|
||||
throw newInternalError("Unknown function: " + func);
|
||||
}
|
||||
@ -636,6 +630,15 @@ class Invokers {
|
||||
}
|
||||
}
|
||||
|
||||
private static NamedFunction getNamedFunction(String name, MethodType type)
|
||||
throws ReflectiveOperationException
|
||||
{
|
||||
MemberName member = new MemberName(Invokers.class, name, type, REF_invokeStatic);
|
||||
return new NamedFunction(
|
||||
MemberName.getFactory()
|
||||
.resolveOrFail(REF_invokeStatic, member, Invokers.class, NoSuchMethodException.class));
|
||||
}
|
||||
|
||||
private static class Lazy {
|
||||
private static final MethodHandle MH_asSpreader;
|
||||
|
||||
|
@ -162,6 +162,29 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
return (MethodType) type;
|
||||
}
|
||||
|
||||
/** Return the descriptor of this member, which
|
||||
* must be a method or constructor.
|
||||
*/
|
||||
String getMethodDescriptor() {
|
||||
if (type == null) {
|
||||
expandFromVM();
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!isInvocable()) {
|
||||
throw newIllegalArgumentException("not invocable, no method type");
|
||||
}
|
||||
|
||||
// Get a snapshot of type which doesn't get changed by racing threads.
|
||||
final Object type = this.type;
|
||||
if (type instanceof String) {
|
||||
return (String) type;
|
||||
} else {
|
||||
return getMethodType().toMethodDescriptorString();
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the actual type under which this method or constructor must be invoked.
|
||||
* For non-static methods or constructors, this is the type with a leading parameter,
|
||||
* a reference to declaring class. For static methods, it is the same as the declared type.
|
||||
|
@ -1785,6 +1785,18 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
return memberName.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodType getMethodType(Object mname) {
|
||||
MemberName memberName = (MemberName)mname;
|
||||
return memberName.getMethodType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodDescriptor(Object mname) {
|
||||
MemberName memberName = (MemberName)mname;
|
||||
return memberName.getMethodDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNative(Object mname) {
|
||||
MemberName memberName = (MemberName)mname;
|
||||
|
@ -211,7 +211,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments i, mod modulus.
|
||||
* Circularly increments i, mod modulus.
|
||||
* Precondition and postcondition: 0 <= i < modulus.
|
||||
*/
|
||||
static final int inc(int i, int modulus) {
|
||||
@ -220,7 +220,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements i, mod modulus.
|
||||
* Circularly decrements i, mod modulus.
|
||||
* Precondition and postcondition: 0 <= i < modulus.
|
||||
*/
|
||||
static final int dec(int i, int modulus) {
|
||||
@ -233,7 +233,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
* Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
|
||||
* @return index 0 <= i < modulus
|
||||
*/
|
||||
static final int add(int i, int distance, int modulus) {
|
||||
static final int inc(int i, int distance, int modulus) {
|
||||
if ((i += distance) - modulus >= 0) i -= modulus;
|
||||
return i;
|
||||
}
|
||||
@ -825,7 +825,7 @@ public class ArrayDeque<E> extends AbstractCollection<E>
|
||||
final int i, n;
|
||||
return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
|
||||
? null
|
||||
: new DeqSpliterator(i, cursor = add(i, n, es.length));
|
||||
: new DeqSpliterator(i, cursor = inc(i, n, es.length));
|
||||
}
|
||||
|
||||
public void forEachRemaining(Consumer<? super E> action) {
|
||||
|
@ -490,7 +490,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Map.putAll and Map constructor
|
||||
* Implements Map.putAll and Map constructor.
|
||||
*
|
||||
* @param m the map
|
||||
* @param evict false when initially constructing this map, else
|
||||
@ -557,7 +557,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Map.get and related methods
|
||||
* Implements Map.get and related methods.
|
||||
*
|
||||
* @param hash hash for key
|
||||
* @param key the key
|
||||
@ -612,7 +612,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Map.put and related methods
|
||||
* Implements Map.put and related methods.
|
||||
*
|
||||
* @param hash hash for key
|
||||
* @param key the key
|
||||
@ -700,7 +700,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
threshold = newThr;
|
||||
@SuppressWarnings({"rawtypes","unchecked"})
|
||||
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
|
||||
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
|
||||
table = newTab;
|
||||
if (oldTab != null) {
|
||||
for (int j = 0; j < oldCap; ++j) {
|
||||
@ -800,7 +800,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Map.remove and related methods
|
||||
* Implements Map.remove and related methods.
|
||||
*
|
||||
* @param hash hash for key
|
||||
* @param key the key
|
||||
@ -875,7 +875,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
public boolean containsValue(Object value) {
|
||||
Node<K,V>[] tab; V v;
|
||||
if ((tab = table) != null && size > 0) {
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next) {
|
||||
if ((v = e.value) == value ||
|
||||
(value != null && value.equals(v)))
|
||||
@ -927,7 +927,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e.key);
|
||||
}
|
||||
@ -975,7 +975,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e.value);
|
||||
}
|
||||
@ -1038,7 +1038,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e);
|
||||
}
|
||||
@ -1335,7 +1335,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e.key, e.value);
|
||||
}
|
||||
@ -1351,7 +1351,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next) {
|
||||
e.value = function.apply(e.key, e.value);
|
||||
}
|
||||
@ -1394,9 +1394,10 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the state of the {@code HashMap} instance to a stream (i.e.,
|
||||
* serialize it).
|
||||
* Saves this map to a stream (that is, serializes it).
|
||||
*
|
||||
* @param s the stream
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @serialData The <i>capacity</i> of the HashMap (the length of the
|
||||
* bucket array) is emitted (int), followed by the
|
||||
* <i>size</i> (an int, the number of key-value
|
||||
@ -1415,8 +1416,11 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstitute the {@code HashMap} instance from a stream (i.e.,
|
||||
* deserialize it).
|
||||
* Reconstitutes this map from a stream (that is, deserializes it).
|
||||
* @param s the stream
|
||||
* @throws ClassNotFoundException if the class of a serialized object
|
||||
* could not be found
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
@ -1445,7 +1449,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
|
||||
(int)ft : Integer.MAX_VALUE);
|
||||
@SuppressWarnings({"rawtypes","unchecked"})
|
||||
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
|
||||
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
|
||||
table = tab;
|
||||
|
||||
// Read the keys and values, and put the mappings in the HashMap
|
||||
@ -1830,7 +1834,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
|
||||
Node<K,V>[] tab;
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next) {
|
||||
s.writeObject(e.key);
|
||||
s.writeObject(e.value);
|
||||
@ -1951,7 +1955,6 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
|
||||
/**
|
||||
* Forms tree of the nodes linked from this node.
|
||||
* @return root of tree
|
||||
*/
|
||||
final void treeify(Node<K,V>[] tab) {
|
||||
TreeNode<K,V> root = null;
|
||||
@ -2089,8 +2092,11 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
return;
|
||||
if (root.parent != null)
|
||||
root = root.root();
|
||||
if (root == null || root.right == null ||
|
||||
(rl = root.left) == null || rl.left == null) {
|
||||
if (root == null
|
||||
|| (movable
|
||||
&& (root.right == null
|
||||
|| (rl = root.left) == null
|
||||
|| rl.left == null))) {
|
||||
tab[index] = first.untreeify(map); // too small
|
||||
return;
|
||||
}
|
||||
@ -2319,7 +2325,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
||||
|
||||
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
|
||||
TreeNode<K,V> x) {
|
||||
for (TreeNode<K,V> xp, xpl, xpr;;) {
|
||||
for (TreeNode<K,V> xp, xpl, xpr;;) {
|
||||
if (x == null || x == root)
|
||||
return root;
|
||||
else if ((xp = x.parent) == null) {
|
||||
|
@ -2490,13 +2490,13 @@ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
|
||||
for (Completion p = stack; p != null; p = p.next)
|
||||
++count;
|
||||
return super.toString() +
|
||||
((r == null) ?
|
||||
((count == 0) ?
|
||||
"[Not completed]" :
|
||||
"[Not completed, " + count + " dependents]") :
|
||||
(((r instanceof AltResult) && ((AltResult)r).ex != null) ?
|
||||
"[Completed exceptionally]" :
|
||||
"[Completed normally]"));
|
||||
((r == null)
|
||||
? ((count == 0)
|
||||
? "[Not completed]"
|
||||
: "[Not completed, " + count + " dependents]")
|
||||
: (((r instanceof AltResult) && ((AltResult)r).ex != null)
|
||||
? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
|
||||
: "[Completed normally]"));
|
||||
}
|
||||
|
||||
// jdk9 additions
|
||||
|
@ -1394,8 +1394,8 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the state of the {@code ConcurrentHashMap} instance to a
|
||||
* stream (i.e., serializes it).
|
||||
* Saves this map to a stream (that is, serializes it).
|
||||
*
|
||||
* @param s the stream
|
||||
* @throws java.io.IOException if an I/O error occurs
|
||||
* @serialData
|
||||
@ -1439,7 +1439,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstitutes the instance from a stream (that is, deserializes it).
|
||||
* Reconstitutes this map from a stream (that is, deserializes it).
|
||||
* @param s the stream
|
||||
* @throws ClassNotFoundException if the class of a serialized object
|
||||
* could not be found
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -174,6 +174,10 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
|
||||
this.completionQueue = completionQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RejectedExecutionException {@inheritDoc}
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public Future<V> submit(Callable<V> task) {
|
||||
if (task == null) throw new NullPointerException();
|
||||
RunnableFuture<V> f = newTaskFor(task);
|
||||
@ -181,6 +185,10 @@ public class ExecutorCompletionService<V> implements CompletionService<V> {
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RejectedExecutionException {@inheritDoc}
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public Future<V> submit(Runnable task, V result) {
|
||||
if (task == null) throw new NullPointerException();
|
||||
RunnableFuture<V> f = newTaskFor(task, result);
|
||||
|
@ -514,6 +514,9 @@ public class Executors {
|
||||
task.run();
|
||||
return result;
|
||||
}
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + task + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -540,6 +543,10 @@ public class Executors {
|
||||
throw e.getException();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + task + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -592,6 +599,10 @@ public class Executors {
|
||||
throw e.getException();
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + task + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1375,6 +1375,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
public final void setRawResult(T v) { result = v; }
|
||||
public final boolean exec() { runnable.run(); return true; }
|
||||
public final void run() { invoke(); }
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + runnable + "]";
|
||||
}
|
||||
private static final long serialVersionUID = 5232453952276885070L;
|
||||
}
|
||||
|
||||
@ -1392,6 +1395,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
public final void setRawResult(Void v) { }
|
||||
public final boolean exec() { runnable.run(); return true; }
|
||||
public final void run() { invoke(); }
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + runnable + "]";
|
||||
}
|
||||
private static final long serialVersionUID = 5232453952276885070L;
|
||||
}
|
||||
|
||||
@ -1437,6 +1443,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
}
|
||||
public final void run() { invoke(); }
|
||||
public String toString() {
|
||||
return super.toString() + "[Wrapped task = " + callable + "]";
|
||||
}
|
||||
private static final long serialVersionUID = 2838392045355241008L;
|
||||
}
|
||||
|
||||
|
@ -480,6 +480,41 @@ public class FutureTask<V> implements RunnableFuture<V> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this FutureTask.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation returns a string identifying this
|
||||
* FutureTask, as well as its completion state. The state, in
|
||||
* brackets, contains one of the strings {@code "Completed Normally"},
|
||||
* {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
|
||||
* "Not completed"}.
|
||||
*
|
||||
* @return a string representation of this FutureTask
|
||||
*/
|
||||
public String toString() {
|
||||
final String status;
|
||||
switch (state) {
|
||||
case NORMAL:
|
||||
status = "[Completed normally]";
|
||||
break;
|
||||
case EXCEPTIONAL:
|
||||
status = "[Completed exceptionally: " + outcome + "]";
|
||||
break;
|
||||
case CANCELLED:
|
||||
case INTERRUPTING:
|
||||
case INTERRUPTED:
|
||||
status = "[Cancelled]";
|
||||
break;
|
||||
default:
|
||||
final Callable<?> callable = this.callable;
|
||||
status = (callable == null)
|
||||
? "[Not completed]"
|
||||
: "[Not completed, task = " + callable + "]";
|
||||
}
|
||||
return super.toString() + status;
|
||||
}
|
||||
|
||||
// VarHandle mechanics
|
||||
private static final VarHandle STATE;
|
||||
private static final VarHandle RUNNER;
|
||||
|
@ -383,7 +383,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
*/
|
||||
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
|
||||
private static final int COUNT_BITS = Integer.SIZE - 3;
|
||||
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
|
||||
private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
|
||||
|
||||
// runState is stored in the high-order bits
|
||||
private static final int RUNNING = -1 << COUNT_BITS;
|
||||
@ -393,8 +393,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
private static final int TERMINATED = 3 << COUNT_BITS;
|
||||
|
||||
// Packing and unpacking ctl
|
||||
private static int runStateOf(int c) { return c & ~CAPACITY; }
|
||||
private static int workerCountOf(int c) { return c & CAPACITY; }
|
||||
private static int runStateOf(int c) { return c & ~COUNT_MASK; }
|
||||
private static int workerCountOf(int c) { return c & COUNT_MASK; }
|
||||
private static int ctlOf(int rs, int wc) { return rs | wc; }
|
||||
|
||||
/*
|
||||
@ -434,7 +434,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* decrements are performed within getTask.
|
||||
*/
|
||||
private void decrementWorkerCount() {
|
||||
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
|
||||
ctl.addAndGet(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -538,12 +538,17 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* Core pool size is the minimum number of workers to keep alive
|
||||
* (and not allow to time out etc) unless allowCoreThreadTimeOut
|
||||
* is set, in which case the minimum is zero.
|
||||
*
|
||||
* Since the worker count is actually stored in COUNT_BITS bits,
|
||||
* the effective limit is {@code corePoolSize & COUNT_MASK}.
|
||||
*/
|
||||
private volatile int corePoolSize;
|
||||
|
||||
/**
|
||||
* Maximum pool size. Note that the actual maximum is internally
|
||||
* bounded by CAPACITY.
|
||||
* Maximum pool size.
|
||||
*
|
||||
* Since the worker count is actually stored in COUNT_BITS bits,
|
||||
* the effective limit is {@code maximumPoolSize & COUNT_MASK}.
|
||||
*/
|
||||
private volatile int maximumPoolSize;
|
||||
|
||||
@ -705,7 +710,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
int c = ctl.get();
|
||||
if (isRunning(c) ||
|
||||
runStateAtLeast(c, TIDYING) ||
|
||||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
|
||||
(runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
|
||||
return;
|
||||
if (workerCountOf(c) != 0) { // Eligible to terminate
|
||||
interruptIdleWorkers(ONLY_ONE);
|
||||
@ -744,17 +749,12 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* specially.
|
||||
*/
|
||||
private void checkShutdownAccess() {
|
||||
// assert mainLock.isHeldByCurrentThread();
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkPermission(shutdownPerm);
|
||||
final ReentrantLock mainLock = this.mainLock;
|
||||
mainLock.lock();
|
||||
try {
|
||||
for (Worker w : workers)
|
||||
security.checkAccess(w.thread);
|
||||
} finally {
|
||||
mainLock.unlock();
|
||||
}
|
||||
for (Worker w : workers)
|
||||
security.checkAccess(w.thread);
|
||||
}
|
||||
}
|
||||
|
||||
@ -763,14 +763,9 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* (in which case some threads may remain uninterrupted).
|
||||
*/
|
||||
private void interruptWorkers() {
|
||||
final ReentrantLock mainLock = this.mainLock;
|
||||
mainLock.lock();
|
||||
try {
|
||||
for (Worker w : workers)
|
||||
w.interruptIfStarted();
|
||||
} finally {
|
||||
mainLock.unlock();
|
||||
}
|
||||
// assert mainLock.isHeldByCurrentThread();
|
||||
for (Worker w : workers)
|
||||
w.interruptIfStarted();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -896,26 +891,22 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
*/
|
||||
private boolean addWorker(Runnable firstTask, boolean core) {
|
||||
retry:
|
||||
for (;;) {
|
||||
int c = ctl.get();
|
||||
int rs = runStateOf(c);
|
||||
|
||||
for (int c = ctl.get();;) {
|
||||
// Check if queue empty only if necessary.
|
||||
if (rs >= SHUTDOWN &&
|
||||
! (rs == SHUTDOWN &&
|
||||
firstTask == null &&
|
||||
! workQueue.isEmpty()))
|
||||
if (runStateAtLeast(c, SHUTDOWN)
|
||||
&& (runStateAtLeast(c, STOP)
|
||||
|| firstTask != null
|
||||
|| workQueue.isEmpty()))
|
||||
return false;
|
||||
|
||||
for (;;) {
|
||||
int wc = workerCountOf(c);
|
||||
if (wc >= CAPACITY ||
|
||||
wc >= (core ? corePoolSize : maximumPoolSize))
|
||||
if (workerCountOf(c)
|
||||
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
|
||||
return false;
|
||||
if (compareAndIncrementWorkerCount(c))
|
||||
break retry;
|
||||
c = ctl.get(); // Re-read ctl
|
||||
if (runStateOf(c) != rs)
|
||||
if (runStateAtLeast(c, SHUTDOWN))
|
||||
continue retry;
|
||||
// else CAS failed due to workerCount change; retry inner loop
|
||||
}
|
||||
@ -934,10 +925,10 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
// Recheck while holding lock.
|
||||
// Back out on ThreadFactory failure or if
|
||||
// shut down before lock acquired.
|
||||
int rs = runStateOf(ctl.get());
|
||||
int c = ctl.get();
|
||||
|
||||
if (rs < SHUTDOWN ||
|
||||
(rs == SHUTDOWN && firstTask == null)) {
|
||||
if (isRunning(c) ||
|
||||
(runStateLessThan(c, STOP) && firstTask == null)) {
|
||||
if (t.isAlive()) // precheck that t is startable
|
||||
throw new IllegalThreadStateException();
|
||||
workers.add(w);
|
||||
@ -1044,10 +1035,10 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
|
||||
for (;;) {
|
||||
int c = ctl.get();
|
||||
int rs = runStateOf(c);
|
||||
|
||||
// Check if queue empty only if necessary.
|
||||
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
|
||||
if (runStateAtLeast(c, SHUTDOWN)
|
||||
&& (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
|
||||
decrementWorkerCount();
|
||||
return null;
|
||||
}
|
||||
@ -1140,17 +1131,12 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
wt.interrupt();
|
||||
try {
|
||||
beforeExecute(wt, task);
|
||||
Throwable thrown = null;
|
||||
try {
|
||||
task.run();
|
||||
} catch (RuntimeException x) {
|
||||
thrown = x; throw x;
|
||||
} catch (Error x) {
|
||||
thrown = x; throw x;
|
||||
} catch (Throwable x) {
|
||||
thrown = x; throw new Error(x);
|
||||
} finally {
|
||||
afterExecute(task, thrown);
|
||||
afterExecute(task, null);
|
||||
} catch (Throwable ex) {
|
||||
afterExecute(task, ex);
|
||||
throw ex;
|
||||
}
|
||||
} finally {
|
||||
task = null;
|
||||
@ -1331,7 +1317,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
*
|
||||
* If the task cannot be submitted for execution, either because this
|
||||
* executor has been shutdown or because its capacity has been reached,
|
||||
* the task is handled by the current {@code RejectedExecutionHandler}.
|
||||
* the task is handled by the current {@link RejectedExecutionHandler}.
|
||||
*
|
||||
* @param command the task to execute
|
||||
* @throws RejectedExecutionException at discretion of
|
||||
@ -1438,7 +1424,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
}
|
||||
|
||||
public boolean isShutdown() {
|
||||
return ! isRunning(ctl.get());
|
||||
return runStateAtLeast(ctl.get(), SHUTDOWN);
|
||||
}
|
||||
|
||||
/** Used by ScheduledThreadPoolExecutor. */
|
||||
@ -1459,7 +1445,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
*/
|
||||
public boolean isTerminating() {
|
||||
int c = ctl.get();
|
||||
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
|
||||
return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
|
||||
}
|
||||
|
||||
public boolean isTerminated() {
|
||||
@ -1472,7 +1458,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
final ReentrantLock mainLock = this.mainLock;
|
||||
mainLock.lock();
|
||||
try {
|
||||
while (!runStateAtLeast(ctl.get(), TERMINATED)) {
|
||||
while (runStateLessThan(ctl.get(), TERMINATED)) {
|
||||
if (nanos <= 0L)
|
||||
return false;
|
||||
nanos = termination.awaitNanos(nanos);
|
||||
@ -1951,7 +1937,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
}
|
||||
int c = ctl.get();
|
||||
String runState =
|
||||
runStateLessThan(c, SHUTDOWN) ? "Running" :
|
||||
isRunning(c) ? "Running" :
|
||||
runStateAtLeast(c, TERMINATED) ? "Terminated" :
|
||||
"Shutting down";
|
||||
return super.toString() +
|
||||
|
@ -342,11 +342,13 @@ public enum TimeUnit {
|
||||
* using:
|
||||
*
|
||||
* <pre> {@code
|
||||
* public synchronized Object poll(long timeout, TimeUnit unit)
|
||||
* public E poll(long timeout, TimeUnit unit)
|
||||
* throws InterruptedException {
|
||||
* while (empty) {
|
||||
* unit.timedWait(this, timeout);
|
||||
* ...
|
||||
* synchronized (lock) {
|
||||
* while (isEmpty()) {
|
||||
* unit.timedWait(lock, timeout);
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* }}</pre>
|
||||
*
|
||||
|
@ -67,11 +67,11 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
private static final long serialVersionUID = 7373984972572414692L;
|
||||
|
||||
/*
|
||||
To keep sources in sync, the remainder of this source file is
|
||||
exactly cloned from AbstractQueuedSynchronizer, replacing class
|
||||
name and changing ints related with sync state to longs. Please
|
||||
keep it that way.
|
||||
*/
|
||||
* To keep sources in sync, the remainder of this source file is
|
||||
* exactly cloned from AbstractQueuedSynchronizer, replacing class
|
||||
* name and changing ints related with sync state to longs. Please
|
||||
* keep it that way.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new {@code AbstractQueuedLongSynchronizer} instance
|
||||
@ -725,8 +725,7 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
/**
|
||||
* Returns {@code true} if synchronization is held exclusively with
|
||||
* respect to the current (calling) thread. This method is invoked
|
||||
* upon each call to a non-waiting {@link ConditionObject} method.
|
||||
* (Waiting methods instead invoke {@link #release}.)
|
||||
* upon each call to a {@link ConditionObject} method.
|
||||
*
|
||||
* <p>The default implementation throws {@link
|
||||
* UnsupportedOperationException}. This method is invoked
|
||||
@ -1366,9 +1365,8 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition implementation for a {@link
|
||||
* AbstractQueuedLongSynchronizer} serving as the basis of a {@link
|
||||
* Lock} implementation.
|
||||
* Condition implementation for a {@link AbstractQueuedLongSynchronizer}
|
||||
* serving as the basis of a {@link Lock} implementation.
|
||||
*
|
||||
* <p>Method documentation for this class describes mechanics,
|
||||
* not behavioral specifications from the point of view of Lock
|
||||
@ -1401,6 +1399,8 @@ public abstract class AbstractQueuedLongSynchronizer
|
||||
* @return its new wait node
|
||||
*/
|
||||
private Node addConditionWaiter() {
|
||||
if (!isHeldExclusively())
|
||||
throw new IllegalMonitorStateException();
|
||||
Node t = lastWaiter;
|
||||
// If lastWaiter is cancelled, clean out.
|
||||
if (t != null && t.waitStatus != Node.CONDITION) {
|
||||
|
@ -194,19 +194,13 @@ import java.util.concurrent.TimeUnit;
|
||||
* represent the locked state. While a non-reentrant lock
|
||||
* does not strictly require recording of the current owner
|
||||
* thread, this class does so anyway to make usage easier to monitor.
|
||||
* It also supports conditions and exposes
|
||||
* one of the instrumentation methods:
|
||||
* It also supports conditions and exposes some instrumentation methods:
|
||||
*
|
||||
* <pre> {@code
|
||||
* class Mutex implements Lock, java.io.Serializable {
|
||||
*
|
||||
* // Our internal helper class
|
||||
* private static class Sync extends AbstractQueuedSynchronizer {
|
||||
* // Reports whether in locked state
|
||||
* protected boolean isHeldExclusively() {
|
||||
* return getState() == 1;
|
||||
* }
|
||||
*
|
||||
* // Acquires the lock if state is zero
|
||||
* public boolean tryAcquire(int acquires) {
|
||||
* assert acquires == 1; // Otherwise unused
|
||||
@ -220,14 +214,27 @@ import java.util.concurrent.TimeUnit;
|
||||
* // Releases the lock by setting state to zero
|
||||
* protected boolean tryRelease(int releases) {
|
||||
* assert releases == 1; // Otherwise unused
|
||||
* if (getState() == 0) throw new IllegalMonitorStateException();
|
||||
* if (!isHeldExclusively())
|
||||
* throw new IllegalMonitorStateException();
|
||||
* setExclusiveOwnerThread(null);
|
||||
* setState(0);
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* // Reports whether in locked state
|
||||
* public boolean isLocked() {
|
||||
* return getState() != 0;
|
||||
* }
|
||||
*
|
||||
* public boolean isHeldExclusively() {
|
||||
* // a data race, but safe due to out-of-thin-air guarantees
|
||||
* return getExclusiveOwnerThread() == Thread.currentThread();
|
||||
* }
|
||||
*
|
||||
* // Provides a Condition
|
||||
* Condition newCondition() { return new ConditionObject(); }
|
||||
* public Condition newCondition() {
|
||||
* return new ConditionObject();
|
||||
* }
|
||||
*
|
||||
* // Deserializes properly
|
||||
* private void readObject(ObjectInputStream s)
|
||||
@ -240,12 +247,17 @@ import java.util.concurrent.TimeUnit;
|
||||
* // The sync object does all the hard work. We just forward to it.
|
||||
* private final Sync sync = new Sync();
|
||||
*
|
||||
* public void lock() { sync.acquire(1); }
|
||||
* public boolean tryLock() { return sync.tryAcquire(1); }
|
||||
* public void unlock() { sync.release(1); }
|
||||
* public Condition newCondition() { return sync.newCondition(); }
|
||||
* public boolean isLocked() { return sync.isHeldExclusively(); }
|
||||
* public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
|
||||
* public void lock() { sync.acquire(1); }
|
||||
* public boolean tryLock() { return sync.tryAcquire(1); }
|
||||
* public void unlock() { sync.release(1); }
|
||||
* public Condition newCondition() { return sync.newCondition(); }
|
||||
* public boolean isLocked() { return sync.isLocked(); }
|
||||
* public boolean isHeldByCurrentThread() {
|
||||
* return sync.isHeldExclusively();
|
||||
* }
|
||||
* public boolean hasQueuedThreads() {
|
||||
* return sync.hasQueuedThreads();
|
||||
* }
|
||||
* public void lockInterruptibly() throws InterruptedException {
|
||||
* sync.acquireInterruptibly(1);
|
||||
* }
|
||||
@ -1193,8 +1205,7 @@ public abstract class AbstractQueuedSynchronizer
|
||||
/**
|
||||
* Returns {@code true} if synchronization is held exclusively with
|
||||
* respect to the current (calling) thread. This method is invoked
|
||||
* upon each call to a non-waiting {@link ConditionObject} method.
|
||||
* (Waiting methods instead invoke {@link #release}.)
|
||||
* upon each call to a {@link ConditionObject} method.
|
||||
*
|
||||
* <p>The default implementation throws {@link
|
||||
* UnsupportedOperationException}. This method is invoked
|
||||
@ -1834,9 +1845,8 @@ public abstract class AbstractQueuedSynchronizer
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition implementation for a {@link
|
||||
* AbstractQueuedSynchronizer} serving as the basis of a {@link
|
||||
* Lock} implementation.
|
||||
* Condition implementation for a {@link AbstractQueuedSynchronizer}
|
||||
* serving as the basis of a {@link Lock} implementation.
|
||||
*
|
||||
* <p>Method documentation for this class describes mechanics,
|
||||
* not behavioral specifications from the point of view of Lock
|
||||
@ -1867,6 +1877,8 @@ public abstract class AbstractQueuedSynchronizer
|
||||
* @return its new wait node
|
||||
*/
|
||||
private Node addConditionWaiter() {
|
||||
if (!isHeldExclusively())
|
||||
throw new IllegalMonitorStateException();
|
||||
Node t = lastWaiter;
|
||||
// If lastWaiter is cancelled, clean out.
|
||||
if (t != null && t.waitStatus != Node.CONDITION) {
|
||||
|
@ -73,7 +73,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* available in the buffer. This can be achieved using two
|
||||
* {@link Condition} instances.
|
||||
* <pre>
|
||||
* class BoundedBuffer {
|
||||
* class BoundedBuffer<E> {
|
||||
* <b>final Lock lock = new ReentrantLock();</b>
|
||||
* final Condition notFull = <b>lock.newCondition(); </b>
|
||||
* final Condition notEmpty = <b>lock.newCondition(); </b>
|
||||
@ -81,7 +81,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* final Object[] items = new Object[100];
|
||||
* int putptr, takeptr, count;
|
||||
*
|
||||
* public void put(Object x) throws InterruptedException {
|
||||
* public void put(E x) throws InterruptedException {
|
||||
* <b>lock.lock();
|
||||
* try {</b>
|
||||
* while (count == items.length)
|
||||
@ -95,12 +95,12 @@ import java.util.concurrent.TimeUnit;
|
||||
* }</b>
|
||||
* }
|
||||
*
|
||||
* public Object take() throws InterruptedException {
|
||||
* public E take() throws InterruptedException {
|
||||
* <b>lock.lock();
|
||||
* try {</b>
|
||||
* while (count == 0)
|
||||
* <b>notEmpty.await();</b>
|
||||
* Object x = items[takeptr];
|
||||
* E x = (E) items[takeptr];
|
||||
* if (++takeptr == items.length) takeptr = 0;
|
||||
* --count;
|
||||
* <b>notFull.signal();</b>
|
||||
@ -310,7 +310,8 @@ public interface Condition {
|
||||
* the following form:
|
||||
*
|
||||
* <pre> {@code
|
||||
* boolean aMethod(long timeout, TimeUnit unit) {
|
||||
* boolean aMethod(long timeout, TimeUnit unit)
|
||||
* throws InterruptedException {
|
||||
* long nanos = unit.toNanos(timeout);
|
||||
* lock.lock();
|
||||
* try {
|
||||
@ -320,6 +321,7 @@ public interface Condition {
|
||||
* nanos = theCondition.awaitNanos(nanos);
|
||||
* }
|
||||
* // ...
|
||||
* return true;
|
||||
* } finally {
|
||||
* lock.unlock();
|
||||
* }
|
||||
@ -410,7 +412,8 @@ public interface Condition {
|
||||
* <p>The return value indicates whether the deadline has elapsed,
|
||||
* which can be used as follows:
|
||||
* <pre> {@code
|
||||
* boolean aMethod(Date deadline) {
|
||||
* boolean aMethod(Date deadline)
|
||||
* throws InterruptedException {
|
||||
* boolean stillWaiting = true;
|
||||
* lock.lock();
|
||||
* try {
|
||||
@ -420,6 +423,7 @@ public interface Condition {
|
||||
* stillWaiting = theCondition.awaitUntil(deadline);
|
||||
* }
|
||||
* // ...
|
||||
* return true;
|
||||
* } finally {
|
||||
* lock.unlock();
|
||||
* }
|
||||
|
@ -151,18 +151,20 @@ import jdk.internal.vm.annotation.ReservedStackAccess;
|
||||
* }
|
||||
*
|
||||
* double distanceFromOrigin() { // A read-only method
|
||||
* double currentX, currentY;
|
||||
* long stamp = sl.tryOptimisticRead();
|
||||
* double currentX = x, currentY = y;
|
||||
* if (!sl.validate(stamp)) {
|
||||
* stamp = sl.readLock();
|
||||
* do {
|
||||
* if (stamp == 0L)
|
||||
* stamp = sl.readLock();
|
||||
* try {
|
||||
* // possibly racy reads
|
||||
* currentX = x;
|
||||
* currentY = y;
|
||||
* } finally {
|
||||
* sl.unlockRead(stamp);
|
||||
* stamp = sl.tryConvertToOptimisticRead(stamp);
|
||||
* }
|
||||
* }
|
||||
* return Math.sqrt(currentX * currentX + currentY * currentY);
|
||||
* } while (stamp == 0);
|
||||
* return Math.hypot(currentX, currentY);
|
||||
* }
|
||||
*
|
||||
* void moveIfAtOrigin(double newX, double newY) { // upgrade
|
||||
|
@ -39,6 +39,18 @@ public interface JavaLangInvokeAccess {
|
||||
*/
|
||||
String getName(Object mname);
|
||||
|
||||
/**
|
||||
* Returns the {@code MethodType} for the given MemberName.
|
||||
* Used by {@see StackFrameInfo}.
|
||||
*/
|
||||
MethodType getMethodType(Object mname);
|
||||
|
||||
/**
|
||||
* Returns the descriptor for the given MemberName.
|
||||
* Used by {@see StackFrameInfo}.
|
||||
*/
|
||||
String getMethodDescriptor(Object mname);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given MemberName is a native method. Used by
|
||||
* {@see StackFrameInfo}.
|
||||
|
@ -1802,7 +1802,12 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
try {
|
||||
readRecord(true);
|
||||
} catch (SocketTimeoutException e) {
|
||||
// if time out, ignore the exception and continue
|
||||
if ((debug != null) && Debug.isOn("ssl")) {
|
||||
System.out.println(
|
||||
Thread.currentThread().getName() +
|
||||
", received Exception: " + e);
|
||||
}
|
||||
fatal((byte)(-1), "Did not receive close_notify from peer", e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, 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
|
||||
@ -28,6 +28,7 @@ package sun.security.util;
|
||||
import java.security.*;
|
||||
import java.util.HashMap;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* This class is used to compute digests on sections of the Manifest.
|
||||
@ -112,8 +113,6 @@ public class ManifestDigester {
|
||||
rawBytes = bytes;
|
||||
entries = new HashMap<>();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
Position pos = new Position();
|
||||
|
||||
if (!findSection(0, pos))
|
||||
@ -131,50 +130,41 @@ public class ManifestDigester {
|
||||
|
||||
if (len > 6) {
|
||||
if (isNameAttr(bytes, start)) {
|
||||
StringBuilder nameBuf = new StringBuilder(sectionLen);
|
||||
ByteArrayOutputStream nameBuf = new ByteArrayOutputStream();
|
||||
nameBuf.write(bytes, start+6, len-6);
|
||||
|
||||
try {
|
||||
nameBuf.append(
|
||||
new String(bytes, start+6, len-6, "UTF8"));
|
||||
|
||||
int i = start + len;
|
||||
if ((i-start) < sectionLen) {
|
||||
if (bytes[i] == '\r') {
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
int i = start + len;
|
||||
if ((i-start) < sectionLen) {
|
||||
if (bytes[i] == '\r') {
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
while ((i-start) < sectionLen) {
|
||||
if (bytes[i++] == ' ') {
|
||||
// name is wrapped
|
||||
int wrapStart = i;
|
||||
while (((i-start) < sectionLen)
|
||||
&& (bytes[i++] != '\n'));
|
||||
if (bytes[i-1] != '\n')
|
||||
return; // XXX: exception?
|
||||
int wrapLen;
|
||||
if (bytes[i-2] == '\r')
|
||||
wrapLen = i-wrapStart-2;
|
||||
else
|
||||
wrapLen = i-wrapStart-1;
|
||||
|
||||
nameBuf.append(new String(bytes, wrapStart,
|
||||
wrapLen, "UTF8"));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
entries.put(nameBuf.toString(),
|
||||
new Entry(start, sectionLen, sectionLenWithBlank,
|
||||
rawBytes));
|
||||
|
||||
} catch (java.io.UnsupportedEncodingException uee) {
|
||||
throw new IllegalStateException(
|
||||
"UTF8 not available on platform");
|
||||
}
|
||||
|
||||
while ((i-start) < sectionLen) {
|
||||
if (bytes[i++] == ' ') {
|
||||
// name is wrapped
|
||||
int wrapStart = i;
|
||||
while (((i-start) < sectionLen)
|
||||
&& (bytes[i++] != '\n'));
|
||||
if (bytes[i-1] != '\n')
|
||||
return; // XXX: exception?
|
||||
int wrapLen;
|
||||
if (bytes[i-2] == '\r')
|
||||
wrapLen = i-wrapStart-2;
|
||||
else
|
||||
wrapLen = i-wrapStart-1;
|
||||
|
||||
nameBuf.write(bytes, wrapStart, wrapLen);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
entries.put(new String(nameBuf.toByteArray(), UTF_8),
|
||||
new Entry(start, sectionLen, sectionLenWithBlank,
|
||||
rawBytes));
|
||||
}
|
||||
}
|
||||
start = pos.startOfNext;
|
||||
|
@ -142,6 +142,10 @@ grant codeBase "jrt:/jdk.dynalink" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant codeBase "jrt:/jdk.httpserver" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant codeBase "jrt:/jdk.internal.le" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
@ -679,14 +679,16 @@ Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
|
||||
}
|
||||
|
||||
/* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */
|
||||
currNanoTime = JVM_NanoTime(env, 0);
|
||||
nanoTimeout -= (currNanoTime - prevNanoTime);
|
||||
if (nanoTimeout < NET_NSEC_PER_MSEC) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
||||
"Accept timed out");
|
||||
return;
|
||||
if (nanoTimeout >= NET_NSEC_PER_MSEC) {
|
||||
currNanoTime = JVM_NanoTime(env, 0);
|
||||
nanoTimeout -= (currNanoTime - prevNanoTime);
|
||||
if (nanoTimeout < NET_NSEC_PER_MSEC) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
|
||||
"Accept timed out");
|
||||
return;
|
||||
}
|
||||
prevNanoTime = currNanoTime;
|
||||
}
|
||||
prevNanoTime = currNanoTime;
|
||||
}
|
||||
|
||||
if (newfd < 0) {
|
||||
|
@ -550,10 +550,10 @@ void
|
||||
fileDescriptorClose(JNIEnv *env, jobject this)
|
||||
{
|
||||
FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
|
||||
HANDLE h = (HANDLE)fd;
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
return;
|
||||
}
|
||||
HANDLE h = (HANDLE)fd;
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
|
@ -216,8 +216,9 @@ public enum SourceVersion {
|
||||
* Character#isJavaIdentifierStart(int)} returns {@code true},
|
||||
* followed only by characters for which {@link
|
||||
* Character#isJavaIdentifierPart(int)} returns {@code true}.
|
||||
* This pattern matches regular identifiers, keywords, and the
|
||||
* literals {@code "true"}, {@code "false"}, and {@code "null"}.
|
||||
* This pattern matches regular identifiers, keywords, restricted
|
||||
* keywords, and the literals {@code "true"}, {@code "false"}, and
|
||||
* {@code "null"}.
|
||||
* The method returns {@code false} for all other strings.
|
||||
*
|
||||
* @param name the string to check
|
||||
@ -251,10 +252,13 @@ public enum SourceVersion {
|
||||
* qualified name in the latest source version. Unlike {@link
|
||||
* #isIdentifier isIdentifier}, this method returns {@code false}
|
||||
* for keywords, boolean literals, and the null literal.
|
||||
* This method returns {@code true} for <i>restricted
|
||||
* keywords</i>.
|
||||
*
|
||||
* @param name the string to check
|
||||
* @return {@code true} if this string is a
|
||||
* syntactically valid name, {@code false} otherwise.
|
||||
* @jls 3.9 Keywords
|
||||
* @jls 6.2 Names and Identifiers
|
||||
*/
|
||||
public static boolean isName(CharSequence name) {
|
||||
@ -266,11 +270,14 @@ public enum SourceVersion {
|
||||
* qualified name in the given source version. Unlike {@link
|
||||
* #isIdentifier isIdentifier}, this method returns {@code false}
|
||||
* for keywords, boolean literals, and the null literal.
|
||||
* This method returns {@code true} for <i>restricted
|
||||
* keywords</i>.
|
||||
*
|
||||
* @param name the string to check
|
||||
* @param version the version to use
|
||||
* @return {@code true} if this string is a
|
||||
* syntactically valid name, {@code false} otherwise.
|
||||
* @jls 3.9 Keywords
|
||||
* @jls 6.2 Names and Identifiers
|
||||
* @since 9
|
||||
*/
|
||||
@ -287,6 +294,8 @@ public enum SourceVersion {
|
||||
/**
|
||||
* Returns whether or not {@code s} is a keyword, boolean literal,
|
||||
* or null literal in the latest source version.
|
||||
* This method returns {@code false} for <i>restricted
|
||||
* keywords</i>.
|
||||
*
|
||||
* @param s the string to check
|
||||
* @return {@code true} if {@code s} is a keyword, or boolean
|
||||
@ -302,6 +311,8 @@ public enum SourceVersion {
|
||||
/**
|
||||
* Returns whether or not {@code s} is a keyword, boolean literal,
|
||||
* or null literal in the given source version.
|
||||
* This method returns {@code false} for <i>restricted
|
||||
* keywords</i>.
|
||||
*
|
||||
* @param s the string to check
|
||||
* @param version the version to use
|
||||
|
@ -87,7 +87,7 @@ public interface ModuleElement extends Element, QualifiedNameable {
|
||||
*
|
||||
* @return {@code true} if this is an open module and {@code
|
||||
* false} otherwise
|
||||
*/ // TODO: add @jls to unnamed module section
|
||||
*/
|
||||
boolean isOpen();
|
||||
|
||||
/**
|
||||
@ -96,7 +96,9 @@ public interface ModuleElement extends Element, QualifiedNameable {
|
||||
*
|
||||
* @return {@code true} if this is an unnamed module and {@code
|
||||
* false} otherwise
|
||||
*/ // TODO: add @jls to unnamed module section
|
||||
*
|
||||
* @jls 7.7.5 Unnamed Modules
|
||||
*/
|
||||
boolean isUnnamed();
|
||||
|
||||
/**
|
||||
|
@ -71,6 +71,7 @@ public class Kinds {
|
||||
HIDDEN(Category.RESOLUTION_TARGET), // not overloaded non-target
|
||||
STATICERR(Category.RESOLUTION_TARGET), // overloaded? target
|
||||
MISSING_ENCL(Category.RESOLUTION), // not overloaded non-target
|
||||
BAD_VAR(Category.RESOLUTION), // not overloaded non-target
|
||||
ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR), // not overloaded non-target
|
||||
WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target
|
||||
WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target
|
||||
|
@ -227,6 +227,7 @@ public enum Source {
|
||||
return compareTo(JDK1_8) <= 0;
|
||||
}
|
||||
public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
|
||||
public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
|
||||
public static SourceVersion toSourceVersion(Source source) {
|
||||
switch(source) {
|
||||
case JDK1_2:
|
||||
|
@ -1616,6 +1616,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
|
||||
public TypeVar(Name name, Symbol owner, Type lower) {
|
||||
super(null, TypeMetadata.EMPTY);
|
||||
Assert.checkNonNull(lower);
|
||||
tsym = new TypeVariableSymbol(0, name, this, owner);
|
||||
this.bound = null;
|
||||
this.lower = lower;
|
||||
@ -1628,6 +1629,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
public TypeVar(TypeSymbol tsym, Type bound, Type lower,
|
||||
TypeMetadata metadata) {
|
||||
super(tsym, metadata);
|
||||
Assert.checkNonNull(lower);
|
||||
this.bound = bound;
|
||||
this.lower = lower;
|
||||
}
|
||||
|
@ -1247,7 +1247,9 @@ public class TypeAnnotations {
|
||||
final TypeAnnotationPosition pos =
|
||||
TypeAnnotationPosition.localVariable(currentLambda,
|
||||
tree.pos);
|
||||
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
|
||||
if (!tree.isImplicitlyTyped()) {
|
||||
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
|
||||
}
|
||||
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
|
||||
final TypeAnnotationPosition pos =
|
||||
TypeAnnotationPosition.exceptionParameter(currentLambda,
|
||||
|
@ -190,6 +190,245 @@ public class Types {
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="projections">
|
||||
|
||||
/**
|
||||
* A projection kind. See {@link TypeProjection}
|
||||
*/
|
||||
enum ProjectionKind {
|
||||
UPWARDS() {
|
||||
@Override
|
||||
ProjectionKind complement() {
|
||||
return DOWNWARDS;
|
||||
}
|
||||
},
|
||||
DOWNWARDS() {
|
||||
@Override
|
||||
ProjectionKind complement() {
|
||||
return UPWARDS;
|
||||
}
|
||||
};
|
||||
|
||||
abstract ProjectionKind complement();
|
||||
}
|
||||
|
||||
/**
|
||||
* This visitor performs upwards and downwards projections on types.
|
||||
*
|
||||
* A projection is defined as a function that takes a type T, a set of type variables V and that
|
||||
* produces another type S.
|
||||
*
|
||||
* An upwards projection maps a type T into a type S such that (i) T has no variables in V,
|
||||
* and (ii) S is an upper bound of T.
|
||||
*
|
||||
* A downwards projection maps a type T into a type S such that (i) T has no variables in V,
|
||||
* and (ii) S is a lower bound of T.
|
||||
*
|
||||
* Note that projections are only allowed to touch variables in V. Theferore it is possible for
|
||||
* a projection to leave its input type unchanged if it does not contain any variables in V.
|
||||
*
|
||||
* Moreover, note that while an upwards projection is always defined (every type as an upper bound),
|
||||
* a downwards projection is not always defined.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
|
||||
* {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
|
||||
* {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
|
||||
* {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
|
||||
*/
|
||||
class TypeProjection extends StructuralTypeMapping<ProjectionKind> {
|
||||
|
||||
List<Type> vars;
|
||||
Set<Type> seen = new HashSet<>();
|
||||
|
||||
public TypeProjection(List<Type> vars) {
|
||||
this.vars = vars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitClassType(ClassType t, ProjectionKind pkind) {
|
||||
if (t.isCompound()) {
|
||||
List<Type> components = directSupertypes(t);
|
||||
List<Type> components1 = components.map(c -> c.map(this, pkind));
|
||||
if (components == components1) return t;
|
||||
else return makeIntersectionType(components1);
|
||||
} else {
|
||||
Type outer = t.getEnclosingType();
|
||||
Type outer1 = visit(outer, pkind);
|
||||
List<Type> typarams = t.getTypeArguments();
|
||||
List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind));
|
||||
if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
|
||||
//not defined
|
||||
return syms.botType;
|
||||
}
|
||||
if (outer1 == outer && typarams1 == typarams) return t;
|
||||
else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
|
||||
@Override
|
||||
protected boolean needsStripping() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected Type makeWildcard(Type upper, Type lower) {
|
||||
BoundKind bk;
|
||||
Type bound;
|
||||
if (upper.hasTag(BOT)) {
|
||||
upper = syms.objectType;
|
||||
}
|
||||
boolean isUpperObject = isSameType(upper, syms.objectType);
|
||||
if (!lower.hasTag(BOT) && isUpperObject) {
|
||||
bound = lower;
|
||||
bk = SUPER;
|
||||
} else {
|
||||
bound = upper;
|
||||
bk = isUpperObject ? UNBOUND : EXTENDS;
|
||||
}
|
||||
return new WildcardType(bound, bk, syms.boundClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
|
||||
if (vars.contains(t)) {
|
||||
try {
|
||||
if (seen.add(t)) {
|
||||
final Type bound;
|
||||
switch (pkind) {
|
||||
case UPWARDS:
|
||||
bound = t.getUpperBound();
|
||||
break;
|
||||
case DOWNWARDS:
|
||||
bound = (t.getLowerBound() == null) ?
|
||||
syms.botType :
|
||||
t.getLowerBound();
|
||||
break;
|
||||
default:
|
||||
Assert.error();
|
||||
return null;
|
||||
}
|
||||
return bound.map(this, pkind);
|
||||
} else {
|
||||
//cycle
|
||||
return syms.objectType;
|
||||
}
|
||||
} finally {
|
||||
seen.remove(t);
|
||||
}
|
||||
} else {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
|
||||
switch (pkind) {
|
||||
case UPWARDS:
|
||||
return wt.isExtendsBound() ?
|
||||
wt.type.map(this, pkind) :
|
||||
syms.objectType;
|
||||
case DOWNWARDS:
|
||||
return wt.isSuperBound() ?
|
||||
wt.type.map(this, pkind) :
|
||||
syms.botType;
|
||||
default:
|
||||
Assert.error();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Type mapTypeArgument(Type t, ProjectionKind pkind) {
|
||||
if (!t.containsAny(vars)) {
|
||||
return t;
|
||||
} else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) {
|
||||
//not defined
|
||||
return syms.botType;
|
||||
} else {
|
||||
Type upper = t.map(this, pkind);
|
||||
Type lower = t.map(this, pkind.complement());
|
||||
return makeWildcard(upper, lower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes an upward projection of given type, and vars. See {@link TypeProjection}.
|
||||
*
|
||||
* @param t the type to be projected
|
||||
* @param vars the set of type variables to be mapped
|
||||
* @return the type obtained as result of the projection
|
||||
*/
|
||||
public Type upward(Type t, List<Type> vars) {
|
||||
return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
|
||||
* This routine is typically used to computed the input set of variables to be used during
|
||||
* an upwards projection (see {@link Types#upward(Type, List)}).
|
||||
*
|
||||
* @param t the type where occurrences of captured variables have to be found
|
||||
* @return the set of captured variables found in t
|
||||
*/
|
||||
public List<Type> captures(Type t) {
|
||||
CaptureScanner cs = new CaptureScanner();
|
||||
Set<Type> captures = new HashSet<>();
|
||||
cs.visit(t, captures);
|
||||
return List.from(captures);
|
||||
}
|
||||
|
||||
/**
|
||||
* This visitor scans a type recursively looking for occurrences of captured type variables.
|
||||
*/
|
||||
class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
|
||||
|
||||
@Override
|
||||
public Void visitType(Type t, Set<Type> types) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitClassType(ClassType t, Set<Type> seen) {
|
||||
if (t.isCompound()) {
|
||||
directSupertypes(t).forEach(s -> visit(s, seen));
|
||||
} else {
|
||||
t.allparams().forEach(ta -> visit(ta, seen));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitArrayType(ArrayType t, Set<Type> seen) {
|
||||
return visit(t.elemtype, seen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitWildcardType(WildcardType t, Set<Type> seen) {
|
||||
visit(t.type, seen);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitTypeVar(TypeVar t, Set<Type> seen) {
|
||||
if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
|
||||
visit(t.getUpperBound(), seen);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCapturedType(CapturedType t, Set<Type> seen) {
|
||||
if (seen.add(t)) {
|
||||
visit(t.getUpperBound(), seen);
|
||||
visit(t.getLowerBound(), seen);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="isUnbounded">
|
||||
/**
|
||||
* Checks that all the arguments to a class are unbounded
|
||||
|
@ -83,6 +83,7 @@ import com.sun.tools.javac.util.DiagnosticSource;
|
||||
import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
|
||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.FOREACHLOOP;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
|
||||
@ -139,7 +140,8 @@ public class Analyzer {
|
||||
enum AnalyzerMode {
|
||||
DIAMOND("diamond", Source::allowDiamond),
|
||||
LAMBDA("lambda", Source::allowLambda),
|
||||
METHOD("method", Source::allowGraphInference);
|
||||
METHOD("method", Source::allowGraphInference),
|
||||
LOCAL("local", Source::allowLocalVariableTypeInference);
|
||||
|
||||
final String opt;
|
||||
final Predicate<Source> sourceFilter;
|
||||
@ -341,11 +343,91 @@ public class Analyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for local variable inference analyzers.
|
||||
*/
|
||||
abstract class RedundantLocalVarTypeAnalyzerBase<X extends JCStatement> extends StatementAnalyzer<X, X> {
|
||||
|
||||
RedundantLocalVarTypeAnalyzerBase(JCTree.Tag tag) {
|
||||
super(AnalyzerMode.LOCAL, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a variable tree into a new declaration using implicit type.
|
||||
*/
|
||||
JCVariableDecl mapVar(JCVariableDecl oldTree, JCVariableDecl newTree){
|
||||
newTree.vartype = null;
|
||||
return newTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze results of local variable inference.
|
||||
*/
|
||||
void processVar(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
|
||||
if (!hasErrors) {
|
||||
if (types.isSameType(oldTree.type, newTree.type)) {
|
||||
log.warning(oldTree, Warnings.LocalRedundantType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This analyzer checks if a local variable declaration has redundant type.
|
||||
*/
|
||||
class RedundantLocalVarTypeAnalyzer extends RedundantLocalVarTypeAnalyzerBase<JCVariableDecl> {
|
||||
|
||||
RedundantLocalVarTypeAnalyzer() {
|
||||
super(VARDEF);
|
||||
}
|
||||
|
||||
boolean match(JCVariableDecl tree){
|
||||
return tree.sym.owner.kind == Kind.MTH &&
|
||||
tree.init != null && !tree.isImplicitlyTyped() &&
|
||||
attr.canInferLocalVarType(tree) == null;
|
||||
}
|
||||
@Override
|
||||
JCVariableDecl map(JCVariableDecl oldTree, JCVariableDecl newTree){
|
||||
return mapVar(oldTree, newTree);
|
||||
}
|
||||
@Override
|
||||
void process(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
|
||||
processVar(oldTree, newTree, hasErrors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This analyzer checks if a for each variable declaration has redundant type.
|
||||
*/
|
||||
class RedundantLocalVarTypeAnalyzerForEach extends RedundantLocalVarTypeAnalyzerBase<JCEnhancedForLoop> {
|
||||
|
||||
RedundantLocalVarTypeAnalyzerForEach() {
|
||||
super(FOREACHLOOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean match(JCEnhancedForLoop tree){
|
||||
return !tree.var.isImplicitlyTyped();
|
||||
}
|
||||
@Override
|
||||
JCEnhancedForLoop map(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree){
|
||||
newTree.var = mapVar(oldTree.var, newTree.var);
|
||||
newTree.body = make.Block(0, List.nil()); //ignore body for analysis purpose
|
||||
return newTree;
|
||||
}
|
||||
@Override
|
||||
void process(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree, boolean hasErrors){
|
||||
processVar(oldTree.var, newTree.var, hasErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
|
||||
new DiamondInitializer(),
|
||||
new LambdaAnalyzer(),
|
||||
new RedundantTypeArgAnalyzer()
|
||||
new RedundantTypeArgAnalyzer(),
|
||||
new RedundantLocalVarTypeAnalyzer(),
|
||||
new RedundantLocalVarTypeAnalyzerForEach()
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -28,9 +28,11 @@ package com.sun.tools.javac.comp;
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Attribute.Compound;
|
||||
import com.sun.tools.javac.code.Attribute.TypeCompound;
|
||||
import com.sun.tools.javac.code.Kinds.KindSelector;
|
||||
import com.sun.tools.javac.code.Scope.WriteableScope;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
|
||||
import com.sun.tools.javac.comp.Check.CheckContext;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
@ -602,7 +604,7 @@ public class Annotate {
|
||||
}
|
||||
|
||||
private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
Type result = attr.attribExpr(tree, env, expectedElementType);
|
||||
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
|
||||
Symbol sym = TreeInfo.symbol(tree);
|
||||
if (sym == null ||
|
||||
TreeInfo.nonstaticSelect(tree) ||
|
||||
@ -616,7 +618,7 @@ public class Annotate {
|
||||
}
|
||||
|
||||
private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
Type result = attr.attribExpr(tree, env, expectedElementType);
|
||||
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
|
||||
if (result.isErroneous()) {
|
||||
// Does it look like an unresolved class literal?
|
||||
if (TreeInfo.name(tree) == names._class &&
|
||||
@ -642,7 +644,7 @@ public class Annotate {
|
||||
}
|
||||
|
||||
private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
Type result = attr.attribExpr(tree, env, expectedElementType);
|
||||
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
|
||||
if (result.isErroneous())
|
||||
return new Attribute.Error(result.getOriginalType());
|
||||
if (result.constValue() == null) {
|
||||
@ -653,6 +655,22 @@ public class Annotate {
|
||||
return new Attribute.Constant(expectedElementType, result.constValue());
|
||||
}
|
||||
|
||||
private Attr.ResultInfo annotationValueInfo(Type pt) {
|
||||
return attr.unknownExprInfo.dup(pt, new AnnotationValueContext(attr.unknownExprInfo.checkContext));
|
||||
}
|
||||
|
||||
class AnnotationValueContext extends Check.NestedCheckContext {
|
||||
AnnotationValueContext(CheckContext enclosingContext) {
|
||||
super(enclosingContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compatible(Type found, Type req, Warner warn) {
|
||||
//handle non-final implicitly-typed vars (will be rejected later on)
|
||||
return found.hasTag(TypeTag.NONE) || super.compatible(found, req, warn);
|
||||
}
|
||||
}
|
||||
|
||||
private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
// Special case, implicit array
|
||||
if (!tree.hasTag(NEWARRAY)) {
|
||||
|
@ -36,7 +36,6 @@ import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.TreeVisitor;
|
||||
import com.sun.source.util.SimpleTreeVisitor;
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Directive.RequiresFlag;
|
||||
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||
import com.sun.tools.javac.code.Scope.WriteableScope;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
@ -46,7 +45,6 @@ import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
|
||||
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
|
||||
import com.sun.tools.javac.comp.Check.CheckContext;
|
||||
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
|
||||
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
|
||||
import com.sun.tools.javac.jvm.*;
|
||||
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
|
||||
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
|
||||
@ -830,6 +828,10 @@ public class Attr extends JCTree.Visitor {
|
||||
final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
|
||||
try {
|
||||
Type itype = attribExpr(variable.init, env, type);
|
||||
if (variable.isImplicitlyTyped()) {
|
||||
//fixup local variable type
|
||||
type = variable.type = variable.sym.type = chk.checkLocalVarType(variable, itype.baseType(), variable.name);
|
||||
}
|
||||
if (itype.constValue() != null) {
|
||||
return coerce(itype, type).constValue();
|
||||
} else {
|
||||
@ -1108,6 +1110,21 @@ public class Attr extends JCTree.Visitor {
|
||||
// parameters have already been entered
|
||||
env.info.scope.enter(tree.sym);
|
||||
} else {
|
||||
if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0) {
|
||||
if (tree.init == null) {
|
||||
//cannot use 'var' without initializer
|
||||
log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
|
||||
tree.vartype = make.Erroneous();
|
||||
} else {
|
||||
Fragment msg = canInferLocalVarType(tree);
|
||||
if (msg != null) {
|
||||
//cannot use 'var' with initializer which require an explicit target
|
||||
//(e.g. lambda, method reference, array initializer).
|
||||
log.error(tree, Errors.CantInferLocalVarType(tree.name, msg));
|
||||
tree.vartype = make.Erroneous();
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
annotate.blockAnnotations();
|
||||
memberEnter.memberEnter(tree, env);
|
||||
@ -1131,7 +1148,7 @@ public class Attr extends JCTree.Visitor {
|
||||
boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
|
||||
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
|
||||
(tree.sym.flags() & PARAMETER) != 0;
|
||||
chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
|
||||
chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
|
||||
|
||||
try {
|
||||
v.getConstValue(); // ensure compile-time constant initializer is evaluated
|
||||
@ -1152,6 +1169,10 @@ public class Attr extends JCTree.Visitor {
|
||||
// marking the variable as undefined.
|
||||
initEnv.info.enclVar = v;
|
||||
attribExpr(tree.init, initEnv, v.type);
|
||||
if (tree.isImplicitlyTyped()) {
|
||||
//fixup local variable type
|
||||
v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = tree.type = v.type;
|
||||
@ -1161,6 +1182,71 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
Fragment canInferLocalVarType(JCVariableDecl tree) {
|
||||
LocalInitScanner lis = new LocalInitScanner();
|
||||
lis.scan(tree.init);
|
||||
return lis.badInferenceMsg;
|
||||
}
|
||||
|
||||
static class LocalInitScanner extends TreeScanner {
|
||||
Fragment badInferenceMsg = null;
|
||||
boolean needsTarget = true;
|
||||
|
||||
@Override
|
||||
public void visitNewArray(JCNewArray tree) {
|
||||
if (tree.elemtype == null && needsTarget) {
|
||||
badInferenceMsg = Fragments.LocalArrayMissingTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambda(JCLambda tree) {
|
||||
if (needsTarget) {
|
||||
badInferenceMsg = Fragments.LocalLambdaMissingTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeCast(JCTypeCast tree) {
|
||||
boolean prevNeedsTarget = needsTarget;
|
||||
try {
|
||||
needsTarget = false;
|
||||
super.visitTypeCast(tree);
|
||||
} finally {
|
||||
needsTarget = prevNeedsTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReference(JCMemberReference tree) {
|
||||
if (needsTarget) {
|
||||
badInferenceMsg = Fragments.LocalMrefMissingTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNewClass(JCNewClass tree) {
|
||||
boolean prevNeedsTarget = needsTarget;
|
||||
try {
|
||||
needsTarget = false;
|
||||
super.visitNewClass(tree);
|
||||
} finally {
|
||||
needsTarget = prevNeedsTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
boolean prevNeedsTarget = needsTarget;
|
||||
try {
|
||||
needsTarget = false;
|
||||
super.visitApply(tree);
|
||||
} finally {
|
||||
needsTarget = prevNeedsTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void visitSkip(JCSkip tree) {
|
||||
result = null;
|
||||
}
|
||||
@ -1243,7 +1329,6 @@ public class Attr extends JCTree.Visitor {
|
||||
//attributing the for-each expression; we mimick this by attributing
|
||||
//the for-each expression first (against original scope).
|
||||
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
|
||||
attribStat(tree.var, loopEnv);
|
||||
chk.checkNonVoid(tree.pos(), exprType);
|
||||
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
|
||||
if (elemtype == null) {
|
||||
@ -1261,6 +1346,15 @@ public class Attr extends JCTree.Visitor {
|
||||
: types.wildUpperBound(iterableParams.head);
|
||||
}
|
||||
}
|
||||
if (tree.var.isImplicitlyTyped()) {
|
||||
Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
|
||||
if (inferredType.isErroneous()) {
|
||||
tree.var.vartype = make.at(tree.var.vartype).Erroneous();
|
||||
} else {
|
||||
tree.var.vartype = make.at(tree.var.vartype).Type(inferredType);
|
||||
}
|
||||
}
|
||||
attribStat(tree.var, loopEnv);
|
||||
chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
|
||||
loopEnv.tree = tree; // before, we were not in loop!
|
||||
attribStat(tree.body, loopEnv);
|
||||
@ -2379,7 +2473,8 @@ public class Attr extends JCTree.Visitor {
|
||||
if (pt().hasTag(ARRAY)) {
|
||||
elemtype = types.elemtype(pt());
|
||||
} else {
|
||||
if (!pt().hasTag(ERROR)) {
|
||||
if (!pt().hasTag(ERROR) &&
|
||||
(env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
|
||||
log.error(tree.pos(),
|
||||
Errors.IllegalInitializerForType(pt()));
|
||||
}
|
||||
@ -2404,7 +2499,7 @@ public class Attr extends JCTree.Visitor {
|
||||
@Override
|
||||
public void visitLambda(final JCLambda that) {
|
||||
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
|
||||
if (pt().hasTag(NONE)) {
|
||||
if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
|
||||
//lambda only allowed in assignment or method invocation/cast context
|
||||
log.error(that.pos(), Errors.UnexpectedLambda);
|
||||
}
|
||||
@ -2837,7 +2932,7 @@ public class Attr extends JCTree.Visitor {
|
||||
@Override
|
||||
public void visitReference(final JCMemberReference that) {
|
||||
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
|
||||
if (pt().hasTag(NONE)) {
|
||||
if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
|
||||
//method reference only allowed in assignment or method invocation/cast context
|
||||
log.error(that.pos(), Errors.UnexpectedMref);
|
||||
}
|
||||
@ -3811,6 +3906,14 @@ public class Attr extends JCTree.Visitor {
|
||||
break;
|
||||
case VAR:
|
||||
VarSymbol v = (VarSymbol)sym;
|
||||
|
||||
if (env.info.enclVar != null
|
||||
&& v.type.hasTag(NONE)) {
|
||||
//self reference to implicitly typed variable declaration
|
||||
log.error(TreeInfo.positionFor(v, env.enclClass), Errors.CantInferLocalVarType(v.name, Fragments.LocalSelfRef));
|
||||
return v.type = types.createErrorType(v.type);
|
||||
}
|
||||
|
||||
// Test (4): if symbol is an instance field of a raw type,
|
||||
// which is being assigned to, issue an unchecked warning if
|
||||
// its type changes under erasure.
|
||||
@ -4135,6 +4238,9 @@ public class Attr extends JCTree.Visitor {
|
||||
public void visitTypeArray(JCArrayTypeTree tree) {
|
||||
Type etype = attribType(tree.elemtype, env);
|
||||
Type type = new ArrayType(etype, syms.arrayClass);
|
||||
if (etype.isErroneous()) {
|
||||
type = types.createErrorType(type);
|
||||
}
|
||||
result = check(tree, type, KindSelector.TYP, resultInfo);
|
||||
}
|
||||
|
||||
@ -4776,7 +4882,7 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
public void visitVarDef(final JCVariableDecl tree) {
|
||||
//System.err.println("validateTypeAnnotations.visitVarDef " + tree);
|
||||
if (tree.sym != null && tree.sym.type != null)
|
||||
if (tree.sym != null && tree.sym.type != null && !tree.isImplicitlyTyped())
|
||||
validateAnnotatedType(tree.vartype, tree.sym.type);
|
||||
scan(tree.mods);
|
||||
scan(tree.vartype);
|
||||
@ -4904,17 +5010,16 @@ public class Attr extends JCTree.Visitor {
|
||||
repeat = false;
|
||||
} else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
|
||||
JCWildcard wc = (JCWildcard) enclTr;
|
||||
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) {
|
||||
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound());
|
||||
} else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
|
||||
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
|
||||
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
|
||||
wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
|
||||
validateAnnotatedType(wc.getBound(), wc.getBound().type);
|
||||
} else {
|
||||
// Nothing to do for UNBOUND
|
||||
}
|
||||
repeat = false;
|
||||
} else if (enclTr.hasTag(TYPEARRAY)) {
|
||||
JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
|
||||
validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType());
|
||||
validateAnnotatedType(art.getType(), art.elemtype.type);
|
||||
repeat = false;
|
||||
} else if (enclTr.hasTag(TYPEUNION)) {
|
||||
JCTypeUnion ut = (JCTypeUnion) enclTr;
|
||||
|
@ -843,26 +843,30 @@ public class Check {
|
||||
List<Type> checkDiamondDenotable(ClassType t) {
|
||||
ListBuffer<Type> buf = new ListBuffer<>();
|
||||
for (Type arg : t.allparams()) {
|
||||
if (!diamondTypeChecker.visit(arg, null)) {
|
||||
if (!checkDenotable(arg)) {
|
||||
buf.append(arg);
|
||||
}
|
||||
}
|
||||
return buf.toList();
|
||||
}
|
||||
|
||||
boolean checkDenotable(Type t) {
|
||||
return denotableChecker.visit(t, null);
|
||||
}
|
||||
// where
|
||||
|
||||
/** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
|
||||
* types. The visit methods return false as soon as a non-denotable type is encountered and true
|
||||
* otherwise.
|
||||
*/
|
||||
private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() {
|
||||
private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
|
||||
@Override
|
||||
public Boolean visitType(Type t, Void s) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Boolean visitClassType(ClassType t, Void s) {
|
||||
if (t.isCompound()) {
|
||||
if (t.isUnion() || t.isIntersection()) {
|
||||
return false;
|
||||
}
|
||||
for (Type targ : t.allparams()) {
|
||||
@ -878,7 +882,7 @@ public class Check {
|
||||
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
|
||||
(i.e cannot have been produced by inference (18.4))
|
||||
*/
|
||||
return t.tsym.owner.type.getTypeArguments().contains(t);
|
||||
return (t.tsym.flags() & SYNTHETIC) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -941,6 +945,17 @@ public class Check {
|
||||
(allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
|
||||
}
|
||||
|
||||
Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
|
||||
//upward project the initializer type
|
||||
t = types.upward(t, types.captures(t));
|
||||
//check that resulting type is not the null type
|
||||
if (t.hasTag(BOT)) {
|
||||
log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
|
||||
return types.createErrorType(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
Type checkMethod(final Type mtype,
|
||||
final Symbol sym,
|
||||
final Env<AttrContext> env,
|
||||
@ -3159,7 +3174,10 @@ public class Check {
|
||||
if (s.kind == PCK)
|
||||
return true;
|
||||
} else if (target == names.TYPE_USE) {
|
||||
if (s.kind == TYP || s.kind == VAR ||
|
||||
if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
|
||||
//cannot type annotate implictly typed locals
|
||||
return false;
|
||||
} else if (s.kind == TYP || s.kind == VAR ||
|
||||
(s.kind == MTH && !s.isConstructor() &&
|
||||
!s.type.getReturnType().hasTag(VOID)) ||
|
||||
(s.kind == MTH && s.isConstructor())) {
|
||||
|
@ -529,7 +529,7 @@ public class Infer {
|
||||
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
|
||||
if (Type.containsAny(upperBounds, vars)) {
|
||||
TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
|
||||
fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null);
|
||||
fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
|
||||
todo.append(uv);
|
||||
uv.setInst(fresh_tvar.type);
|
||||
} else if (upperBounds.nonEmpty()) {
|
||||
|
@ -259,7 +259,7 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
try {
|
||||
if (TreeInfo.isEnumInit(tree)) {
|
||||
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
|
||||
} else {
|
||||
} else if (!tree.isImplicitlyTyped()) {
|
||||
attr.attribType(tree.vartype, localEnv);
|
||||
if (TreeInfo.isReceiverParam(tree))
|
||||
checkReceiver(tree, localEnv);
|
||||
@ -279,8 +279,8 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
tree.vartype.type = atype.makeVarargs();
|
||||
}
|
||||
WriteableScope enclScope = enter.enterScope(env);
|
||||
VarSymbol v =
|
||||
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
|
||||
Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
|
||||
VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
|
||||
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
|
||||
tree.sym = v;
|
||||
if (tree.init != null) {
|
||||
@ -298,7 +298,9 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
|
||||
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
|
||||
if (!tree.isImplicitlyTyped()) {
|
||||
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
|
||||
}
|
||||
|
||||
v.pos = tree.pos;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
@ -105,6 +106,7 @@ public class Resolve {
|
||||
public final boolean allowModules;
|
||||
public final boolean checkVarargsAccessAfterResolution;
|
||||
private final boolean compactMethodDiags;
|
||||
private final boolean allowLocalVariableTypeInference;
|
||||
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
|
||||
|
||||
WriteableScope polymorphicSignatureScope;
|
||||
@ -116,7 +118,7 @@ public class Resolve {
|
||||
varNotFound = new SymbolNotFoundError(ABSENT_VAR);
|
||||
methodNotFound = new SymbolNotFoundError(ABSENT_MTH);
|
||||
typeNotFound = new SymbolNotFoundError(ABSENT_TYP);
|
||||
referenceNotFound = new ReferenceLookupResult(methodNotFound, null);
|
||||
referenceNotFound = ReferenceLookupResult.error(methodNotFound);
|
||||
|
||||
names = Names.instance(context);
|
||||
log = Log.instance(context);
|
||||
@ -136,6 +138,7 @@ public class Resolve {
|
||||
Target target = Target.instance(context);
|
||||
allowMethodHandles = target.hasMethodHandles();
|
||||
allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
|
||||
allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
|
||||
checkVarargsAccessAfterResolution =
|
||||
source.allowPostApplicabilityVarargsAccessCheck();
|
||||
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
|
||||
@ -2325,6 +2328,10 @@ public class Resolve {
|
||||
* (a subset of VAL, TYP, PCK).
|
||||
*/
|
||||
Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
|
||||
return checkVarType(findIdentInternal(env, name, kind), name);
|
||||
}
|
||||
|
||||
Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) {
|
||||
Symbol bestSoFar = typeNotFound;
|
||||
Symbol sym;
|
||||
|
||||
@ -2354,6 +2361,11 @@ public class Resolve {
|
||||
*/
|
||||
Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
|
||||
Name name, KindSelector kind) {
|
||||
return checkVarType(findIdentInPackageInternal(env, pck, name, kind), name);
|
||||
}
|
||||
|
||||
Symbol findIdentInPackageInternal(Env<AttrContext> env, TypeSymbol pck,
|
||||
Name name, KindSelector kind) {
|
||||
Name fullname = TypeSymbol.formFullName(name, pck);
|
||||
Symbol bestSoFar = typeNotFound;
|
||||
if (kind.contains(KindSelector.TYP)) {
|
||||
@ -2383,6 +2395,11 @@ public class Resolve {
|
||||
*/
|
||||
Symbol findIdentInType(Env<AttrContext> env, Type site,
|
||||
Name name, KindSelector kind) {
|
||||
return checkVarType(findIdentInTypeInternal(env, site, name, kind), name);
|
||||
}
|
||||
|
||||
Symbol findIdentInTypeInternal(Env<AttrContext> env, Type site,
|
||||
Name name, KindSelector kind) {
|
||||
Symbol bestSoFar = typeNotFound;
|
||||
Symbol sym;
|
||||
if (kind.contains(KindSelector.VAL)) {
|
||||
@ -2399,6 +2416,14 @@ public class Resolve {
|
||||
return bestSoFar;
|
||||
}
|
||||
|
||||
private Symbol checkVarType(Symbol bestSoFar, Name name) {
|
||||
if (allowLocalVariableTypeInference && name.equals(names.var) &&
|
||||
(bestSoFar.kind == TYP || bestSoFar.kind == ABSENT_TYP)) {
|
||||
bestSoFar = new BadVarTypeError();
|
||||
}
|
||||
return bestSoFar;
|
||||
}
|
||||
|
||||
/* ***************************************************************************
|
||||
* Access checking
|
||||
* The following methods convert ResolveErrors to ErrorSymbols, issuing
|
||||
@ -2944,10 +2969,10 @@ public class Resolve {
|
||||
|
||||
//merge results
|
||||
Pair<Symbol, ReferenceLookupHelper> res;
|
||||
Symbol bestSym = referenceChooser.result(boundRes, unboundRes);
|
||||
res = new Pair<>(bestSym,
|
||||
bestSym == unboundSym ? unboundLookupHelper : boundLookupHelper);
|
||||
env.info.pendingResolutionPhase = bestSym == unboundSym ?
|
||||
ReferenceLookupResult bestRes = referenceChooser.result(boundRes, unboundRes);
|
||||
res = new Pair<>(bestRes.sym,
|
||||
bestRes == unboundRes ? unboundLookupHelper : boundLookupHelper);
|
||||
env.info.pendingResolutionPhase = bestRes == unboundRes ?
|
||||
unboundEnv.info.pendingResolutionPhase :
|
||||
boundEnv.info.pendingResolutionPhase;
|
||||
|
||||
@ -3003,11 +3028,15 @@ public class Resolve {
|
||||
Symbol sym;
|
||||
|
||||
ReferenceLookupResult(Symbol sym, MethodResolutionContext resolutionContext) {
|
||||
this.staticKind = staticKind(sym, resolutionContext);
|
||||
this(sym, staticKind(sym, resolutionContext));
|
||||
}
|
||||
|
||||
private ReferenceLookupResult(Symbol sym, StaticKind staticKind) {
|
||||
this.staticKind = staticKind;
|
||||
this.sym = sym;
|
||||
}
|
||||
|
||||
private StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
|
||||
private static StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
|
||||
switch (sym.kind) {
|
||||
case MTH:
|
||||
case AMBIGUOUS:
|
||||
@ -3056,6 +3085,10 @@ public class Resolve {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static ReferenceLookupResult error(Symbol sym) {
|
||||
return new ReferenceLookupResult(sym, StaticKind.UNDEFINED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3068,7 +3101,7 @@ public class Resolve {
|
||||
* Generate a result from a pair of lookup result objects. This method delegates to the
|
||||
* appropriate result generation routine.
|
||||
*/
|
||||
Symbol result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||
ReferenceLookupResult result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||
return unboundRes != referenceNotFound ?
|
||||
unboundResult(boundRes, unboundRes) :
|
||||
boundResult(boundRes);
|
||||
@ -3077,12 +3110,12 @@ public class Resolve {
|
||||
/**
|
||||
* Generate a symbol from a given bound lookup result.
|
||||
*/
|
||||
abstract Symbol boundResult(ReferenceLookupResult boundRes);
|
||||
abstract ReferenceLookupResult boundResult(ReferenceLookupResult boundRes);
|
||||
|
||||
/**
|
||||
* Generate a symbol from a pair of bound/unbound lookup results.
|
||||
*/
|
||||
abstract Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
|
||||
abstract ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3092,37 +3125,38 @@ public class Resolve {
|
||||
ReferenceChooser basicReferenceChooser = new ReferenceChooser() {
|
||||
|
||||
@Override
|
||||
Symbol boundResult(ReferenceLookupResult boundRes) {
|
||||
ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
|
||||
return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ?
|
||||
boundRes.sym : //the search produces a non-static method
|
||||
new BadMethodReferenceError(boundRes.sym, false);
|
||||
boundRes : //the search produces a non-static method
|
||||
ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||
ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||
if (boundRes.hasKind(StaticKind.STATIC) &&
|
||||
(!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
|
||||
//the first search produces a static method and no non-static method is applicable
|
||||
//during the second search
|
||||
return boundRes.sym;
|
||||
return boundRes;
|
||||
} else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
|
||||
(!boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC))) {
|
||||
//the second search produces a non-static method and no static method is applicable
|
||||
//during the first search
|
||||
return unboundRes.sym;
|
||||
return unboundRes;
|
||||
} else if (boundRes.isSuccess() && unboundRes.isSuccess()) {
|
||||
//both searches produce some result; ambiguity (error recovery)
|
||||
return ambiguityError(boundRes.sym, unboundRes.sym);
|
||||
return ReferenceLookupResult.error(ambiguityError(boundRes.sym, unboundRes.sym));
|
||||
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
|
||||
//Both searches failed to produce a result with correct staticness (i.e. first search
|
||||
//produces an non-static method). Alternatively, a given search produced a result
|
||||
//with the right staticness, but the other search has applicable methods with wrong
|
||||
//staticness (error recovery)
|
||||
return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
|
||||
return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
|
||||
boundRes.sym : unboundRes.sym, true));
|
||||
} else {
|
||||
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
|
||||
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
|
||||
unboundRes.sym : boundRes.sym;
|
||||
unboundRes : boundRes;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -3134,28 +3168,29 @@ public class Resolve {
|
||||
ReferenceChooser structuralReferenceChooser = new ReferenceChooser() {
|
||||
|
||||
@Override
|
||||
Symbol boundResult(ReferenceLookupResult boundRes) {
|
||||
ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
|
||||
return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ?
|
||||
boundRes.sym : //the search has at least one applicable non-static method
|
||||
new BadMethodReferenceError(boundRes.sym, false);
|
||||
boundRes : //the search has at least one applicable non-static method
|
||||
ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||
ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||
if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) {
|
||||
//the first serach has at least one applicable static method
|
||||
return boundRes.sym;
|
||||
return boundRes;
|
||||
} else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) {
|
||||
//the second search has at least one applicable non-static method
|
||||
return unboundRes.sym;
|
||||
return unboundRes;
|
||||
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
|
||||
//either the first search produces a non-static method, or second search produces
|
||||
//a non-static method (error recovery)
|
||||
return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
|
||||
return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
|
||||
boundRes.sym : unboundRes.sym, true));
|
||||
} else {
|
||||
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
|
||||
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
|
||||
unboundRes.sym : boundRes.sym;
|
||||
unboundRes : boundRes;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -3774,6 +3809,17 @@ public class Resolve {
|
||||
}
|
||||
}
|
||||
|
||||
class BadVarTypeError extends ResolveError {
|
||||
BadVarTypeError() {
|
||||
super(Kind.BAD_VAR, "bad var use");
|
||||
}
|
||||
|
||||
@Override
|
||||
JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
|
||||
return diags.create(dkind, log.currentSource(), pos, "illegal.ref.to.var.type", name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* InvalidSymbolError error class indicating that a symbol matching a
|
||||
* given name does not exists in a given site.
|
||||
@ -3995,14 +4041,35 @@ public class Resolve {
|
||||
}
|
||||
//where
|
||||
private Map<Symbol, JCDiagnostic> mapCandidates() {
|
||||
Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>();
|
||||
MostSpecificMap candidates = new MostSpecificMap();
|
||||
for (Candidate c : resolveContext.candidates) {
|
||||
if (c.isApplicable()) continue;
|
||||
candidates.put(c.sym, c.details);
|
||||
candidates.put(c);
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private class MostSpecificMap extends LinkedHashMap<Symbol, JCDiagnostic> {
|
||||
private void put(Candidate c) {
|
||||
ListBuffer<Symbol> overridden = new ListBuffer<>();
|
||||
for (Symbol s : keySet()) {
|
||||
if (s == c.sym) {
|
||||
continue;
|
||||
}
|
||||
if (c.sym.overrides(s, (TypeSymbol)s.owner, types, false)) {
|
||||
overridden.add(s);
|
||||
} else if (s.overrides(c.sym, (TypeSymbol)c.sym.owner, types, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (Symbol s : overridden) {
|
||||
remove(s);
|
||||
}
|
||||
put(c.sym, c.details);
|
||||
}
|
||||
}
|
||||
|
||||
Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) {
|
||||
Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>();
|
||||
for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {
|
||||
|
@ -179,6 +179,7 @@ public class JavacParser implements Parser {
|
||||
this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
|
||||
this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
|
||||
this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
|
||||
this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
|
||||
this.keepDocComments = keepDocComments;
|
||||
this.parseModuleInfo = parseModuleInfo;
|
||||
docComments = newDocCommentTable(keepDocComments, fac);
|
||||
@ -270,11 +271,14 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
boolean allowThisIdent;
|
||||
|
||||
/** Switch: is local variable inference allowed?
|
||||
*/
|
||||
boolean allowLocalVariableTypeInference;
|
||||
|
||||
/** The type of the method receiver, as specified by a first "this" parameter.
|
||||
*/
|
||||
JCVariableDecl receiverParam;
|
||||
|
||||
|
||||
/** When terms are parsed, the mode determines which is expected:
|
||||
* mode = EXPR : an expression
|
||||
* mode = TYPE : a type
|
||||
@ -808,12 +812,16 @@ public class JavacParser implements Parser {
|
||||
* parsing annotations.
|
||||
*/
|
||||
public JCExpression parseType() {
|
||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||
return parseType(annotations);
|
||||
return parseType(false);
|
||||
}
|
||||
|
||||
public JCExpression parseType(List<JCAnnotation> annotations) {
|
||||
JCExpression result = unannotatedType();
|
||||
public JCExpression parseType(boolean allowVar) {
|
||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||
return parseType(allowVar, annotations);
|
||||
}
|
||||
|
||||
public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
|
||||
JCExpression result = unannotatedType(allowVar);
|
||||
|
||||
if (annotations.nonEmpty()) {
|
||||
result = insertAnnotationsToMostInner(result, annotations, false);
|
||||
@ -822,10 +830,18 @@ public class JavacParser implements Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
public JCExpression unannotatedType() {
|
||||
return term(TYPE);
|
||||
public JCExpression unannotatedType(boolean allowVar) {
|
||||
JCExpression result = term(TYPE);
|
||||
|
||||
if (!allowVar && isRestrictedLocalVarTypeName(result)) {
|
||||
syntaxError(result.pos, "var.not.allowed.here");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected JCExpression term(int newmode) {
|
||||
int prevmode = mode;
|
||||
mode = newmode;
|
||||
@ -1152,11 +1168,11 @@ public class JavacParser implements Parser {
|
||||
accept(LPAREN);
|
||||
mode = TYPE;
|
||||
int pos1 = pos;
|
||||
List<JCExpression> targets = List.of(t = term3());
|
||||
List<JCExpression> targets = List.of(t = parseType());
|
||||
while (token.kind == AMP) {
|
||||
checkIntersectionTypesInCast();
|
||||
accept(AMP);
|
||||
targets = targets.prepend(term3());
|
||||
targets = targets.prepend(parseType());
|
||||
}
|
||||
if (targets.length() > 1) {
|
||||
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
|
||||
@ -1912,7 +1928,7 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
JCExpression typeArgument() {
|
||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||
if (token.kind != QUES) return parseType(annotations);
|
||||
if (token.kind != QUES) return parseType(false, annotations);
|
||||
int pos = token.pos;
|
||||
nextToken();
|
||||
JCExpression result;
|
||||
@ -2425,13 +2441,8 @@ public class JavacParser implements Parser {
|
||||
token.kind == ENUM) {
|
||||
return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
|
||||
} else {
|
||||
JCExpression t = parseType();
|
||||
ListBuffer<JCStatement> stats =
|
||||
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
|
||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
||||
accept(SEMI);
|
||||
storeEnd(stats.last(), S.prevToken().endPos);
|
||||
return stats.toList();
|
||||
JCExpression t = parseType(true);
|
||||
return localVariableDeclarations(mods, t);
|
||||
}
|
||||
}
|
||||
case ABSTRACT: case STRICTFP: {
|
||||
@ -2458,12 +2469,7 @@ public class JavacParser implements Parser {
|
||||
pos = token.pos;
|
||||
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
|
||||
F.at(pos);
|
||||
ListBuffer<JCStatement> stats =
|
||||
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
|
||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
||||
accept(SEMI);
|
||||
storeEnd(stats.last(), S.prevToken().endPos);
|
||||
return stats.toList();
|
||||
return localVariableDeclarations(mods, t);
|
||||
} else {
|
||||
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
|
||||
t = checkExprStat(t);
|
||||
@ -2473,6 +2479,15 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
}
|
||||
}
|
||||
//where
|
||||
private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
|
||||
ListBuffer<JCStatement> stats =
|
||||
variableDeclarators(mods, type, new ListBuffer<>(), true);
|
||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
||||
accept(SEMI);
|
||||
storeEnd(stats.last(), S.prevToken().endPos);
|
||||
return stats.toList();
|
||||
}
|
||||
|
||||
/** Statement =
|
||||
* Block
|
||||
@ -2766,11 +2781,11 @@ public class JavacParser implements Parser {
|
||||
ListBuffer<JCStatement> stats = new ListBuffer<>();
|
||||
int pos = token.pos;
|
||||
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
||||
return variableDeclarators(optFinal(0), parseType(), stats).toList();
|
||||
return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
|
||||
} else {
|
||||
JCExpression t = term(EXPR | TYPE);
|
||||
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
|
||||
return variableDeclarators(modifiersOpt(), t, stats).toList();
|
||||
return variableDeclarators(modifiersOpt(), t, stats, true).toList();
|
||||
} else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
|
||||
error(pos, "bad.initializer", "for-loop");
|
||||
return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
|
||||
@ -2989,9 +3004,10 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
|
||||
JCExpression type,
|
||||
T vdefs)
|
||||
T vdefs,
|
||||
boolean localDecl)
|
||||
{
|
||||
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
|
||||
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
|
||||
}
|
||||
|
||||
/** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
|
||||
@ -3006,14 +3022,20 @@ public class JavacParser implements Parser {
|
||||
Name name,
|
||||
boolean reqInit,
|
||||
Comment dc,
|
||||
T vdefs)
|
||||
T vdefs,
|
||||
boolean localDecl)
|
||||
{
|
||||
vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
|
||||
JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
|
||||
boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
|
||||
vdefs.append(head);
|
||||
while (token.kind == COMMA) {
|
||||
if (implicit) {
|
||||
reportSyntaxError(pos, "var.not.allowed.compound");
|
||||
}
|
||||
// All but last of multiple declarators subsume a comma
|
||||
storeEnd((JCTree)vdefs.last(), token.endPos);
|
||||
nextToken();
|
||||
vdefs.append(variableDeclarator(mods, type, reqInit, dc));
|
||||
vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
|
||||
}
|
||||
return vdefs;
|
||||
}
|
||||
@ -3021,8 +3043,8 @@ public class JavacParser implements Parser {
|
||||
/** VariableDeclarator = Ident VariableDeclaratorRest
|
||||
* ConstantDeclarator = Ident ConstantDeclaratorRest
|
||||
*/
|
||||
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
|
||||
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
|
||||
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
|
||||
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
|
||||
}
|
||||
|
||||
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
|
||||
@ -3032,7 +3054,7 @@ public class JavacParser implements Parser {
|
||||
* @param dc The documentation comment for the variable declarations, or null.
|
||||
*/
|
||||
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
|
||||
boolean reqInit, Comment dc) {
|
||||
boolean reqInit, Comment dc, boolean localDecl) {
|
||||
type = bracketsOpt(type);
|
||||
JCExpression init = null;
|
||||
if (token.kind == EQ) {
|
||||
@ -3040,12 +3062,40 @@ public class JavacParser implements Parser {
|
||||
init = variableInitializer();
|
||||
}
|
||||
else if (reqInit) syntaxError(token.pos, "expected", EQ);
|
||||
JCTree elemType = TreeInfo.innermostType(type, true);
|
||||
if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
|
||||
Name typeName = ((JCIdent)elemType).name;
|
||||
if (isRestrictedLocalVarTypeName(typeName)) {
|
||||
if (type.hasTag(TYPEARRAY)) {
|
||||
//error - 'var' and arrays
|
||||
reportSyntaxError(pos, "var.not.allowed.array");
|
||||
} else {
|
||||
//implicit type
|
||||
type = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
JCVariableDecl result =
|
||||
toP(F.at(pos).VarDef(mods, name, type, init));
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean isRestrictedLocalVarTypeName(JCExpression e) {
|
||||
switch (e.getTag()) {
|
||||
case IDENT:
|
||||
return isRestrictedLocalVarTypeName(((JCIdent)e).name);
|
||||
case TYPEARRAY:
|
||||
return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isRestrictedLocalVarTypeName(Name name) {
|
||||
return allowLocalVariableTypeInference && name == names.var;
|
||||
}
|
||||
|
||||
/** VariableDeclaratorId = Ident BracketsOpt
|
||||
*/
|
||||
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
|
||||
@ -3111,13 +3161,13 @@ public class JavacParser implements Parser {
|
||||
int startPos = token.pos;
|
||||
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
||||
JCModifiers mods = optFinal(Flags.FINAL);
|
||||
JCExpression t = parseType();
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
|
||||
JCExpression t = parseType(true);
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
|
||||
}
|
||||
JCExpression t = term(EXPR | TYPE);
|
||||
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
|
||||
JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
|
||||
} else {
|
||||
checkVariableInTryWithResources(startPos);
|
||||
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
|
||||
@ -3397,7 +3447,7 @@ public class JavacParser implements Parser {
|
||||
protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
|
||||
int pos = token.pos;
|
||||
accept(CLASS);
|
||||
Name name = ident();
|
||||
Name name = typeName();
|
||||
|
||||
List<JCTypeParameter> typarams = typeParametersOpt();
|
||||
|
||||
@ -3418,6 +3468,15 @@ public class JavacParser implements Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
Name typeName() {
|
||||
int pos = token.pos;
|
||||
Name name = ident();
|
||||
if (isRestrictedLocalVarTypeName(name)) {
|
||||
reportSyntaxError(pos, "var.not.allowed", name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
|
||||
* [EXTENDS TypeList] InterfaceBody
|
||||
* @param mods The modifiers starting the interface declaration
|
||||
@ -3426,7 +3485,8 @@ public class JavacParser implements Parser {
|
||||
protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
|
||||
int pos = token.pos;
|
||||
accept(INTERFACE);
|
||||
Name name = ident();
|
||||
|
||||
Name name = typeName();
|
||||
|
||||
List<JCTypeParameter> typarams = typeParametersOpt();
|
||||
|
||||
@ -3449,7 +3509,8 @@ public class JavacParser implements Parser {
|
||||
protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
|
||||
int pos = token.pos;
|
||||
accept(ENUM);
|
||||
Name name = ident();
|
||||
|
||||
Name name = typeName();
|
||||
|
||||
List<JCExpression> implementing = List.nil();
|
||||
if (token.kind == IMPLEMENTS) {
|
||||
@ -3647,7 +3708,7 @@ public class JavacParser implements Parser {
|
||||
nextToken();
|
||||
} else {
|
||||
// method returns types are un-annotated types
|
||||
type = unannotatedType();
|
||||
type = unannotatedType(false);
|
||||
}
|
||||
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
|
||||
if (isInterface || tk.name() != className)
|
||||
@ -3667,7 +3728,7 @@ public class JavacParser implements Parser {
|
||||
} else if (!isVoid && typarams.isEmpty()) {
|
||||
List<JCTree> defs =
|
||||
variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
|
||||
new ListBuffer<JCTree>()).toList();
|
||||
new ListBuffer<JCTree>(), false).toList();
|
||||
accept(SEMI);
|
||||
storeEnd(defs.last(), S.prevToken().endPos);
|
||||
return defs;
|
||||
@ -3809,7 +3870,7 @@ public class JavacParser implements Parser {
|
||||
JCTypeParameter typeParameter() {
|
||||
int pos = token.pos;
|
||||
List<JCAnnotation> annos = typeAnnotationsOpt();
|
||||
Name name = ident();
|
||||
Name name = typeName();
|
||||
ListBuffer<JCExpression> bounds = new ListBuffer<>();
|
||||
if (token.kind == EXTENDS) {
|
||||
nextToken();
|
||||
|
@ -1190,6 +1190,47 @@ compiler.err.io.exception=\
|
||||
compiler.err.undef.label=\
|
||||
undefined label: {0}
|
||||
|
||||
# 0: name (type)
|
||||
compiler.err.illegal.ref.to.var.type=\
|
||||
illegal reference to restricted type ''{0}''
|
||||
|
||||
# 0: token
|
||||
compiler.err.var.not.allowed=\
|
||||
''{0}'' not allowed here\n\
|
||||
as of release 10, ''{0}'' is a restricted local variable type and cannot be used for type declarations
|
||||
|
||||
# 0: name (variable), 1: message segment
|
||||
compiler.err.cant.infer.local.var.type=\
|
||||
cannot infer type for local variable {0}\n\
|
||||
({1})
|
||||
|
||||
compiler.err.var.not.allowed.here=\
|
||||
''var'' is not allowed here
|
||||
|
||||
compiler.err.var.not.allowed.array=\
|
||||
''var'' is not allowed as an element type of an array
|
||||
|
||||
compiler.err.var.not.allowed.compound=\
|
||||
''var'' is not allowed in a compound declaration
|
||||
|
||||
compiler.misc.local.cant.infer.null=\
|
||||
variable initializer is ''null''
|
||||
|
||||
compiler.misc.local.missing.init=\
|
||||
cannot use ''var'' on variable without initializer
|
||||
|
||||
compiler.misc.local.lambda.missing.target=\
|
||||
lambda expression needs an explicit target-type
|
||||
|
||||
compiler.misc.local.mref.missing.target=\
|
||||
method reference needs an explicit target-type
|
||||
|
||||
compiler.misc.local.array.missing.target=\
|
||||
array initializer needs an explicit target-type
|
||||
|
||||
compiler.misc.local.self.ref=\
|
||||
cannot use ''var'' on self-referencing variable
|
||||
|
||||
# 0: message segment, 1: unused
|
||||
compiler.err.cant.apply.diamond=\
|
||||
cannot infer type arguments for {0}
|
||||
@ -1873,6 +1914,9 @@ compiler.warn.raw.class.use=\
|
||||
compiler.warn.diamond.redundant.args=\
|
||||
Redundant type arguments in new expression (use diamond operator instead).
|
||||
|
||||
compiler.warn.local.redundant.type=\
|
||||
Redundant type for local variable (replace explicit type with ''var'').
|
||||
|
||||
compiler.warn.potential.lambda.found=\
|
||||
This anonymous inner class creation can be turned into a lambda expression.
|
||||
|
||||
|
@ -946,6 +946,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isImplicitlyTyped() {
|
||||
return vartype == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) { v.visitVarDef(this); }
|
||||
|
||||
|
@ -1359,7 +1359,7 @@ public class Pretty extends JCTree.Visitor {
|
||||
|
||||
// Prints the inner element type of a nested array
|
||||
private void printBaseElementType(JCTree tree) throws IOException {
|
||||
printExpr(TreeInfo.innermostType(tree));
|
||||
printExpr(TreeInfo.innermostType(tree, false));
|
||||
}
|
||||
|
||||
// prints the brackets of a nested array in reverse order
|
||||
|
@ -1136,7 +1136,7 @@ public class TreeInfo {
|
||||
* For an array that contains an annotated type, return that annotated type.
|
||||
* TODO: currently only used by Pretty. Describe behavior better.
|
||||
*/
|
||||
public static JCTree innermostType(JCTree type) {
|
||||
public static JCTree innermostType(JCTree type, boolean skipAnnos) {
|
||||
JCTree lastAnnotatedType = null;
|
||||
JCTree cur = type;
|
||||
loop: while (true) {
|
||||
@ -1157,7 +1157,7 @@ public class TreeInfo {
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (lastAnnotatedType!=null) {
|
||||
if (!skipAnnos && lastAnnotatedType!=null) {
|
||||
return lastAnnotatedType;
|
||||
} else {
|
||||
return cur;
|
||||
|
@ -63,6 +63,7 @@ public class Names {
|
||||
public final Name _default;
|
||||
public final Name _super;
|
||||
public final Name _this;
|
||||
public final Name var;
|
||||
public final Name exports;
|
||||
public final Name opens;
|
||||
public final Name module;
|
||||
@ -224,6 +225,7 @@ public class Names {
|
||||
_default = fromString("default");
|
||||
_super = fromString("super");
|
||||
_this = fromString("this");
|
||||
var = fromString("var");
|
||||
exports = fromString("exports");
|
||||
opens = fromString("opens");
|
||||
module = fromString("module");
|
||||
|
@ -106,7 +106,8 @@ module jdk.compiler {
|
||||
exports com.sun.tools.javac.jvm to
|
||||
jdk.javadoc;
|
||||
exports com.sun.tools.javac.main to
|
||||
jdk.javadoc;
|
||||
jdk.javadoc,
|
||||
jdk.jshell;
|
||||
exports com.sun.tools.javac.model to
|
||||
jdk.javadoc;
|
||||
exports com.sun.tools.javac.parser to
|
||||
|
@ -39,6 +39,7 @@ import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.type.TypeVariable;
|
||||
import javax.lang.model.util.SimpleTypeVisitor9;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||
@ -98,15 +99,19 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
|
||||
*/
|
||||
@Override
|
||||
protected Content getDeprecatedLink(Element member) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(utils.getFullyQualifiedName(member));
|
||||
Content deprecatedLinkContent = new ContentBuilder();
|
||||
deprecatedLinkContent.addContent(utils.getFullyQualifiedName(member));
|
||||
if (!utils.isConstructor(member)) {
|
||||
sb.append(".");
|
||||
sb.append(member.getSimpleName());
|
||||
deprecatedLinkContent.addContent(".");
|
||||
deprecatedLinkContent.addContent(member.getSimpleName());
|
||||
}
|
||||
sb.append(utils.flatSignature((ExecutableElement) member));
|
||||
String signature = utils.flatSignature((ExecutableElement) member);
|
||||
if (signature.length() > 2) {
|
||||
deprecatedLinkContent.addContent(Contents.ZERO_WIDTH_SPACE);
|
||||
}
|
||||
deprecatedLinkContent.addContent(signature);
|
||||
|
||||
return writer.getDocLink(MEMBER, member, sb);
|
||||
return writer.getDocLink(MEMBER, utils.getEnclosingTypeElement(member), member, deprecatedLinkContent);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,55 +204,61 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
|
||||
*/
|
||||
protected void addParameters(ExecutableElement member,
|
||||
boolean includeAnnotations, Content htmltree, int indentSize) {
|
||||
htmltree.addContent(Contents.ZERO_WIDTH_SPACE);
|
||||
htmltree.addContent("(");
|
||||
Content paramTree = new ContentBuilder();
|
||||
String sep = "";
|
||||
List<? extends VariableElement> parameters = member.getParameters();
|
||||
CharSequence indent = makeSpace(indentSize + 1);
|
||||
TypeMirror rcvrType = member.getReceiverType();
|
||||
if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) {
|
||||
List<? extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors();
|
||||
addReceiverAnnotations(member, rcvrType, annotationMirrors, htmltree);
|
||||
addReceiverAnnotations(member, rcvrType, annotationMirrors, paramTree);
|
||||
sep = "," + DocletConstants.NL + indent;
|
||||
}
|
||||
int paramstart;
|
||||
for (paramstart = 0; paramstart < parameters.size(); paramstart++) {
|
||||
htmltree.addContent(sep);
|
||||
paramTree.addContent(sep);
|
||||
VariableElement param = parameters.get(paramstart);
|
||||
|
||||
if (param.getKind() != ElementKind.INSTANCE_INIT) {
|
||||
if (includeAnnotations) {
|
||||
boolean foundAnnotations =
|
||||
writer.addAnnotationInfo(indent.length(),
|
||||
member, param, htmltree);
|
||||
member, param, paramTree);
|
||||
if (foundAnnotations) {
|
||||
htmltree.addContent(DocletConstants.NL);
|
||||
htmltree.addContent(indent);
|
||||
paramTree.addContent(DocletConstants.NL);
|
||||
paramTree.addContent(indent);
|
||||
}
|
||||
}
|
||||
addParam(member, param,
|
||||
(paramstart == parameters.size() - 1) && member.isVarArgs(), htmltree);
|
||||
(paramstart == parameters.size() - 1) && member.isVarArgs(), paramTree);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = paramstart + 1; i < parameters.size(); i++) {
|
||||
htmltree.addContent(",");
|
||||
htmltree.addContent(DocletConstants.NL);
|
||||
htmltree.addContent(indent);
|
||||
paramTree.addContent(",");
|
||||
paramTree.addContent(DocletConstants.NL);
|
||||
paramTree.addContent(indent);
|
||||
if (includeAnnotations) {
|
||||
boolean foundAnnotations =
|
||||
writer.addAnnotationInfo(indent.length(), member, parameters.get(i),
|
||||
htmltree);
|
||||
paramTree);
|
||||
if (foundAnnotations) {
|
||||
htmltree.addContent(DocletConstants.NL);
|
||||
htmltree.addContent(indent);
|
||||
paramTree.addContent(DocletConstants.NL);
|
||||
paramTree.addContent(indent);
|
||||
}
|
||||
}
|
||||
addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(),
|
||||
htmltree);
|
||||
paramTree);
|
||||
}
|
||||
if (paramTree.isEmpty()) {
|
||||
htmltree.addContent("()");
|
||||
} else {
|
||||
htmltree.addContent(Contents.ZERO_WIDTH_SPACE);
|
||||
htmltree.addContent("(");
|
||||
htmltree.addContent(paramTree);
|
||||
paramTree.addContent(")");
|
||||
}
|
||||
htmltree.addContent(")");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -364,7 +364,7 @@ public class AbstractIndexWriter extends HtmlDocletWriter {
|
||||
List<? extends DocTree> tags;
|
||||
Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element));
|
||||
HtmlTree div = new HtmlTree(HtmlTag.DIV);
|
||||
div.addStyle(HtmlStyle.block);
|
||||
div.addStyle(HtmlStyle.deprecationBlock);
|
||||
if (utils.isDeprecated(element)) {
|
||||
div.addContent(span);
|
||||
tags = utils.getBlockTags(element, DocTree.Kind.DEPRECATED);
|
||||
|
@ -355,7 +355,7 @@ public abstract class AbstractMemberWriter {
|
||||
writer.getTagletWriterInstance(false));
|
||||
if (!output.isEmpty()) {
|
||||
Content deprecatedContent = output;
|
||||
Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent);
|
||||
Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprecatedContent);
|
||||
contentTree.addContent(div);
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +278,8 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter
|
||||
*/
|
||||
@Override
|
||||
public void addAnnotationTypeSignature(String modifiers, Content annotationInfoTree) {
|
||||
annotationInfoTree.addContent(new HtmlTree(HtmlTag.BR));
|
||||
Content hr = new HtmlTree(HtmlTag.HR);
|
||||
annotationInfoTree.addContent(hr);
|
||||
Content pre = new HtmlTree(HtmlTag.PRE);
|
||||
addAnnotationInfo(annotationType, pre);
|
||||
pre.addContent(modifiers);
|
||||
@ -324,18 +325,15 @@ public class AnnotationTypeWriterImpl extends SubWriterHolderWriter
|
||||
*/
|
||||
@Override
|
||||
public void addAnnotationTypeDeprecationInfo(Content annotationInfoTree) {
|
||||
Content hr = new HtmlTree(HtmlTag.HR);
|
||||
annotationInfoTree.addContent(hr);
|
||||
List<? extends DocTree> deprs = utils.getBlockTags(annotationType, DocTree.Kind.DEPRECATED);
|
||||
if (utils.isDeprecated(annotationType)) {
|
||||
CommentHelper ch = utils.getCommentHelper(annotationType);
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(annotationType));
|
||||
Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
|
||||
if (!deprs.isEmpty()) {
|
||||
|
||||
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
|
||||
if (!commentTags.isEmpty()) {
|
||||
div.addContent(Contents.SPACE);
|
||||
addInlineDeprecatedComment(annotationType, deprs.get(0), div);
|
||||
}
|
||||
}
|
||||
|
@ -293,7 +293,8 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
|
||||
*/
|
||||
@Override
|
||||
public void addClassSignature(String modifiers, Content classInfoTree) {
|
||||
classInfoTree.addContent(new HtmlTree(HtmlTag.BR));
|
||||
Content hr = new HtmlTree(HtmlTag.HR);
|
||||
classInfoTree.addContent(hr);
|
||||
Content pre = new HtmlTree(HtmlTag.PRE);
|
||||
addAnnotationInfo(typeElement, pre);
|
||||
pre.addContent(modifiers);
|
||||
@ -606,18 +607,15 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
|
||||
*/
|
||||
@Override
|
||||
public void addClassDeprecationInfo(Content classInfoTree) {
|
||||
Content hr = new HtmlTree(HtmlTag.HR);
|
||||
classInfoTree.addContent(hr);
|
||||
List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
|
||||
if (utils.isDeprecated(typeElement)) {
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement));
|
||||
Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
|
||||
if (!deprs.isEmpty()) {
|
||||
CommentHelper ch = utils.getCommentHelper(typeElement);
|
||||
DocTree dt = deprs.get(0);
|
||||
List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
|
||||
if (!commentTags.isEmpty()) {
|
||||
div.addContent(Contents.SPACE);
|
||||
addInlineDeprecatedComment(typeElement, deprs.get(0), div);
|
||||
}
|
||||
}
|
||||
|
@ -100,33 +100,33 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
private String getHeadingKey(DeprElementKind kind) {
|
||||
switch (kind) {
|
||||
case REMOVAL:
|
||||
return "doclet.Deprecated_For_Removal";
|
||||
return "doclet.For_Removal";
|
||||
case MODULE:
|
||||
return "doclet.Deprecated_Modules";
|
||||
return "doclet.Modules";
|
||||
case PACKAGE:
|
||||
return "doclet.Deprecated_Packages";
|
||||
return "doclet.Packages";
|
||||
case INTERFACE:
|
||||
return "doclet.Deprecated_Interfaces";
|
||||
return "doclet.Interfaces";
|
||||
case CLASS:
|
||||
return "doclet.Deprecated_Classes";
|
||||
return "doclet.Classes";
|
||||
case ENUM:
|
||||
return "doclet.Deprecated_Enums";
|
||||
return "doclet.Enums";
|
||||
case EXCEPTION:
|
||||
return "doclet.Deprecated_Exceptions";
|
||||
return "doclet.Exceptions";
|
||||
case ERROR:
|
||||
return "doclet.Deprecated_Errors";
|
||||
return "doclet.Errors";
|
||||
case ANNOTATION_TYPE:
|
||||
return "doclet.Deprecated_Annotation_Types";
|
||||
return "doclet.Annotation_Types";
|
||||
case FIELD:
|
||||
return "doclet.Deprecated_Fields";
|
||||
return "doclet.Fields";
|
||||
case METHOD:
|
||||
return "doclet.Deprecated_Methods";
|
||||
return "doclet.Methods";
|
||||
case CONSTRUCTOR:
|
||||
return "doclet.Deprecated_Constructors";
|
||||
return "doclet.Constructors";
|
||||
case ENUM_CONSTANT:
|
||||
return "doclet.Deprecated_Enum_Constants";
|
||||
return "doclet.Enum_Constants";
|
||||
case ANNOTATION_TYPE_MEMBER:
|
||||
return "doclet.Deprecated_Annotation_Type_Members";
|
||||
return "doclet.Annotation_Type_Members";
|
||||
default:
|
||||
throw new AssertionError("unknown kind: " + kind);
|
||||
}
|
||||
@ -135,33 +135,33 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
private String getSummaryKey(DeprElementKind kind) {
|
||||
switch (kind) {
|
||||
case REMOVAL:
|
||||
return "doclet.deprecated_for_removal";
|
||||
return "doclet.for_removal";
|
||||
case MODULE:
|
||||
return "doclet.deprecated_modules";
|
||||
return "doclet.modules";
|
||||
case PACKAGE:
|
||||
return "doclet.deprecated_packages";
|
||||
return "doclet.packages";
|
||||
case INTERFACE:
|
||||
return "doclet.deprecated_interfaces";
|
||||
return "doclet.interfaces";
|
||||
case CLASS:
|
||||
return "doclet.deprecated_classes";
|
||||
return "doclet.classes";
|
||||
case ENUM:
|
||||
return "doclet.deprecated_enums";
|
||||
return "doclet.enums";
|
||||
case EXCEPTION:
|
||||
return "doclet.deprecated_exceptions";
|
||||
return "doclet.exceptions";
|
||||
case ERROR:
|
||||
return "doclet.deprecated_errors";
|
||||
return "doclet.errors";
|
||||
case ANNOTATION_TYPE:
|
||||
return "doclet.deprecated_annotation_types";
|
||||
return "doclet.annotation_types";
|
||||
case FIELD:
|
||||
return "doclet.deprecated_fields";
|
||||
return "doclet.fields";
|
||||
case METHOD:
|
||||
return "doclet.deprecated_methods";
|
||||
return "doclet.methods";
|
||||
case CONSTRUCTOR:
|
||||
return "doclet.deprecated_constructors";
|
||||
return "doclet.constructors";
|
||||
case ENUM_CONSTANT:
|
||||
return "doclet.deprecated_enum_constants";
|
||||
return "doclet.enum_constants";
|
||||
case ANNOTATION_TYPE_MEMBER:
|
||||
return "doclet.deprecated_annotation_type_members";
|
||||
return "doclet.annotation_type_members";
|
||||
default:
|
||||
throw new AssertionError("unknown kind: " + kind);
|
||||
}
|
||||
@ -473,6 +473,6 @@ public class DeprecatedListWriter extends SubWriterHolderWriter {
|
||||
default:
|
||||
writer = new AnnotationTypeOptionalMemberWriterImpl(this, null);
|
||||
}
|
||||
return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, writer.getDeprecatedLink(e));
|
||||
return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colDeprecatedItemName, writer.getDeprecatedLink(e));
|
||||
}
|
||||
}
|
||||
|
@ -1715,8 +1715,7 @@ public class HtmlDocletWriter extends HtmlDocWriter {
|
||||
Content div;
|
||||
Content result = commentTagsToContent(null, element, tags, first);
|
||||
if (depr) {
|
||||
Content italic = HtmlTree.SPAN(HtmlStyle.deprecationComment, result);
|
||||
div = HtmlTree.DIV(HtmlStyle.block, italic);
|
||||
div = HtmlTree.DIV(HtmlStyle.deprecationComment, result);
|
||||
htmltree.addContent(div);
|
||||
}
|
||||
else {
|
||||
|
@ -929,7 +929,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
|
||||
if (utils.isDeprecated(mdle)) {
|
||||
CommentHelper ch = utils.getCommentHelper(mdle);
|
||||
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
|
||||
deprDiv.addStyle(HtmlStyle.deprecatedContent);
|
||||
deprDiv.addStyle(HtmlStyle.deprecationBlock);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle));
|
||||
deprDiv.addContent(deprPhrase);
|
||||
if (!deprs.isEmpty()) {
|
||||
@ -1064,7 +1064,7 @@ public class ModuleWriterImpl extends HtmlDocletWriter implements ModuleSummaryW
|
||||
if (utils.isDeprecated(pkg)) {
|
||||
deprs = utils.getDeprecatedTrees(pkg);
|
||||
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
|
||||
deprDiv.addStyle(HtmlStyle.deprecatedContent);
|
||||
deprDiv.addStyle(HtmlStyle.deprecationBlock);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg));
|
||||
deprDiv.addContent(deprPhrase);
|
||||
if (!deprs.isEmpty()) {
|
||||
|
@ -171,7 +171,7 @@ public class PackageWriterImpl extends HtmlDocletWriter
|
||||
if (utils.isDeprecated(packageElement)) {
|
||||
CommentHelper ch = utils.getCommentHelper(packageElement);
|
||||
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
|
||||
deprDiv.addStyle(HtmlStyle.deprecatedContent);
|
||||
deprDiv.addStyle(HtmlStyle.deprecationBlock);
|
||||
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement));
|
||||
deprDiv.addContent(deprPhrase);
|
||||
if (!deprs.isEmpty()) {
|
||||
|
@ -189,9 +189,8 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
|
||||
if (utils.isDeprecated(member)) {
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member));
|
||||
div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
div.addContent(Contents.SPACE);
|
||||
if (!deprs.isEmpty()) {
|
||||
addInlineDeprecatedComment(member, deprs.get(0), div);
|
||||
addSummaryDeprecatedComment(member, deprs.get(0), div);
|
||||
}
|
||||
tdSummary.addContent(div);
|
||||
return;
|
||||
@ -200,7 +199,6 @@ public abstract class SubWriterHolderWriter extends HtmlDocletWriter {
|
||||
if (te != null && utils.isTypeElement(te) && utils.isDeprecated(te)) {
|
||||
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(te));
|
||||
div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
|
||||
div.addContent(Contents.SPACE);
|
||||
tdSummary.addContent(div);
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +179,6 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
if (utils.isDeprecated(element)) {
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||
htmlWriter.getDeprecatedPhrase(element)));
|
||||
result.addContent(RawHtml.nbsp);
|
||||
if (!deprs.isEmpty()) {
|
||||
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
|
||||
if (!commentTags.isEmpty()) {
|
||||
@ -191,19 +190,17 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
if (utils.isDeprecated(element)) {
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||
htmlWriter.getDeprecatedPhrase(element)));
|
||||
result.addContent(RawHtml.nbsp);
|
||||
if (!deprs.isEmpty()) {
|
||||
List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0));
|
||||
Content body = commentTagsToOutput(null, element, bodyTags, false);
|
||||
if (!body.isEmpty())
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecationComment, body));
|
||||
result.addContent(HtmlTree.DIV(HtmlStyle.deprecationComment, body));
|
||||
}
|
||||
} else {
|
||||
Element ee = utils.getEnclosingTypeElement(element);
|
||||
if (utils.isDeprecated(ee)) {
|
||||
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||
htmlWriter.getDeprecatedPhrase(ee)));
|
||||
result.addContent(RawHtml.nbsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,15 +47,16 @@ public enum HtmlStyle {
|
||||
circle,
|
||||
classUseContainer,
|
||||
colConstructorName,
|
||||
colDeprecatedItemName,
|
||||
colFirst,
|
||||
colLast,
|
||||
colSecond,
|
||||
constantsSummary,
|
||||
constantValuesContainer,
|
||||
contentContainer,
|
||||
deprecatedContent,
|
||||
deprecatedLabel,
|
||||
deprecatedSummary,
|
||||
deprecationBlock,
|
||||
deprecationComment,
|
||||
description,
|
||||
descfrmTypeLabel,
|
||||
|
@ -74,34 +74,12 @@ doclet.see.class_or_package_not_found=Tag {0}: reference not found: {1}
|
||||
doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
|
||||
doclet.tag.invalid_usage=invalid usage of tag {0}
|
||||
doclet.Deprecated_API=Deprecated API
|
||||
doclet.Deprecated_For_Removal=Deprecated For Removal
|
||||
doclet.Deprecated_Modules=Deprecated Modules
|
||||
doclet.Deprecated_Packages=Deprecated Packages
|
||||
doclet.Deprecated_Classes=Deprecated Classes
|
||||
doclet.Deprecated_Enums=Deprecated Enums
|
||||
doclet.Deprecated_Interfaces=Deprecated Interfaces
|
||||
doclet.Deprecated_Exceptions=Deprecated Exceptions
|
||||
doclet.Deprecated_Annotation_Types=Deprecated Annotation Types
|
||||
doclet.Deprecated_Errors=Deprecated Errors
|
||||
doclet.Deprecated_Fields=Deprecated Fields
|
||||
doclet.Deprecated_Constructors=Deprecated Constructors
|
||||
doclet.Deprecated_Methods=Deprecated Methods
|
||||
doclet.Deprecated_Enum_Constants=Deprecated Enum Constants
|
||||
doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements
|
||||
doclet.deprecated_for_removal=deprecated for removal
|
||||
doclet.deprecated_modules=deprecated modules
|
||||
doclet.deprecated_packages=deprecated packages
|
||||
doclet.deprecated_classes=deprecated classes
|
||||
doclet.deprecated_enums=deprecated enums
|
||||
doclet.deprecated_interfaces=deprecated interfaces
|
||||
doclet.deprecated_exceptions=deprecated exceptions
|
||||
doclet.deprecated_annotation_types=deprecated annotation types
|
||||
doclet.deprecated_errors=deprecated errors
|
||||
doclet.deprecated_fields=deprecated fields
|
||||
doclet.deprecated_constructors=deprecated constructors
|
||||
doclet.deprecated_methods=deprecated methods
|
||||
doclet.deprecated_enum_constants=deprecated enum constants
|
||||
doclet.deprecated_annotation_type_members=deprecated annotation type elements
|
||||
doclet.For_Removal=For Removal
|
||||
doclet.Annotation_Types=Annotation Types
|
||||
doclet.Annotation_Type_Members=Annotation Type Elements
|
||||
doclet.for_removal=for removal
|
||||
doclet.annotation_types=annotation types
|
||||
doclet.annotation_type_members=annotation type elements
|
||||
doclet.Generated_Docs_Untitled=Generated Documentation (Untitled)
|
||||
doclet.Other_Packages=Other Packages
|
||||
doclet.Description=Description
|
||||
|
@ -147,8 +147,8 @@ public class AnnotationTypeBuilder extends AbstractBuilder {
|
||||
throws DocletException {
|
||||
Content annotationInfoTree = writer.getAnnotationInfoTreeHeader();
|
||||
|
||||
buildDeprecationInfo(annotationInfoTree);
|
||||
buildAnnotationTypeSignature(annotationInfoTree);
|
||||
buildDeprecationInfo(annotationInfoTree);
|
||||
buildAnnotationTypeDescription(annotationInfoTree);
|
||||
buildAnnotationTypeTagInfo(annotationInfoTree);
|
||||
|
||||
|
@ -175,8 +175,8 @@ public class ClassBuilder extends AbstractBuilder {
|
||||
buildInterfaceUsageInfo(classInfoTree);
|
||||
buildNestedClassInfo(classInfoTree);
|
||||
buildFunctionalInterfaceInfo(classInfoTree);
|
||||
buildDeprecationInfo(classInfoTree);
|
||||
buildClassSignature(classInfoTree);
|
||||
buildDeprecationInfo(classInfoTree);
|
||||
buildClassDescription(classInfoTree);
|
||||
buildClassTagInfo(classInfoTree);
|
||||
|
||||
|
@ -531,14 +531,16 @@ Table styles
|
||||
text-align:left;
|
||||
padding:0px 0px 12px 10px;
|
||||
}
|
||||
th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .useSummary th, .constantsSummary th, .packagesSummary th,
|
||||
td.colFirst, td.colSecond, td.colLast, .useSummary td, .constantsSummary td {
|
||||
th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .useSummary th,
|
||||
.constantsSummary th, .packagesSummary th, td.colFirst, td.colSecond, td.colLast, .useSummary td,
|
||||
.constantsSummary td {
|
||||
vertical-align:top;
|
||||
padding-right:0px;
|
||||
padding-top:8px;
|
||||
padding-bottom:3px;
|
||||
}
|
||||
th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .constantsSummary th, .packagesSummary th {
|
||||
th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .constantsSummary th,
|
||||
.packagesSummary th {
|
||||
background:#dee3e9;
|
||||
text-align:left;
|
||||
padding:8px 3px 3px 7px;
|
||||
@ -547,7 +549,7 @@ td.colFirst, th.colFirst {
|
||||
white-space:nowrap;
|
||||
font-size:13px;
|
||||
}
|
||||
td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colLast {
|
||||
td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colDeprecatedItemName, th.colLast {
|
||||
font-size:13px;
|
||||
}
|
||||
.constantsSummary th, .packagesSummary th {
|
||||
@ -576,6 +578,7 @@ td.colSecond a:link, td.colSecond a:visited,
|
||||
th.colFirst a:link, th.colFirst a:visited,
|
||||
th.colSecond a:link, th.colSecond a:visited,
|
||||
th.colConstructorName a:link, th.colConstructorName a:visited,
|
||||
th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited,
|
||||
.constantValuesContainer td a:link, .constantValuesContainer td a:visited {
|
||||
font-weight:bold;
|
||||
}
|
||||
@ -645,8 +648,19 @@ h1.hidden {
|
||||
.deprecationComment, .emphasizedPhrase, .interfaceName {
|
||||
font-style:italic;
|
||||
}
|
||||
.deprecationBlock {
|
||||
font-size:14px;
|
||||
font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
|
||||
border-style:solid;
|
||||
border-width:thin;
|
||||
border-radius:10px;
|
||||
padding:10px;
|
||||
margin-bottom:10px;
|
||||
margin-right:10px;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,
|
||||
div.block div.deprecationComment, div.block div.block span.emphasizedPhrase,
|
||||
div.block div.block span.interfaceName {
|
||||
font-style:normal;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ public class DeprecatedAPIListBuilder {
|
||||
deprecatedMap = new EnumMap<>(DeprElementKind.class);
|
||||
for (DeprElementKind kind : DeprElementKind.values()) {
|
||||
deprecatedMap.put(kind,
|
||||
new TreeSet<>(utils.makeGeneralPurposeComparator()));
|
||||
new TreeSet<>(utils.makeDeprecatedComparator()));
|
||||
}
|
||||
buildDeprecatedAPIInfo();
|
||||
}
|
||||
|
@ -1733,6 +1733,25 @@ public class Utils {
|
||||
return packageComparator;
|
||||
}
|
||||
|
||||
private Comparator<Element> deprecatedComparator = null;
|
||||
/**
|
||||
* Returns a Comparator for deprecated items listed on deprecated list page, by comparing the
|
||||
* fully qualified names.
|
||||
*
|
||||
* @return a Comparator
|
||||
*/
|
||||
public Comparator<Element> makeDeprecatedComparator() {
|
||||
if (deprecatedComparator == null) {
|
||||
deprecatedComparator = new Utils.ElementComparator() {
|
||||
@Override
|
||||
public int compare(Element e1, Element e2) {
|
||||
return compareFullyQualifiedNames(e1, e2);
|
||||
}
|
||||
};
|
||||
}
|
||||
return deprecatedComparator;
|
||||
}
|
||||
|
||||
private Comparator<SerialFieldTree> serialFieldTreeComparator = null;
|
||||
/**
|
||||
* Returns a Comparator for SerialFieldTree.
|
||||
|
@ -234,49 +234,6 @@ class JdepsTask {
|
||||
}
|
||||
},
|
||||
|
||||
new Option(true, CommandOption.CHECK_MODULES) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
Set<String> mods = Set.of(arg.split(","));
|
||||
task.options.addmods.addAll(mods);
|
||||
task.command = task.checkModuleDeps(mods);
|
||||
}
|
||||
},
|
||||
new Option(true, CommandOption.GENERATE_MODULE_INFO) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.genModuleInfo(Paths.get(arg), false);
|
||||
}
|
||||
},
|
||||
new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.genModuleInfo(Paths.get(arg), true);
|
||||
}
|
||||
},
|
||||
new Option(false, CommandOption.LIST_DEPS) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.listModuleDeps(false);
|
||||
}
|
||||
},
|
||||
new Option(false, CommandOption.LIST_REDUCED_DEPS) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.listModuleDeps(true);
|
||||
}
|
||||
},
|
||||
|
||||
// ---- paths option ----
|
||||
new Option(true, "-cp", "-classpath", "--class-path") {
|
||||
void process(JdepsTask task, String opt, String arg) {
|
||||
@ -312,15 +269,6 @@ class JdepsTask {
|
||||
task.options.addmods.addAll(mods);
|
||||
}
|
||||
},
|
||||
new Option(true, "-m", "--module") {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (!task.options.rootModules.isEmpty()) {
|
||||
throw new BadArgs("err.option.already.specified", opt);
|
||||
}
|
||||
task.options.rootModules.add(arg);
|
||||
task.options.addmods.add(arg);
|
||||
}
|
||||
},
|
||||
new Option(true, "--multi-release") {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (arg.equalsIgnoreCase("base")) {
|
||||
@ -338,6 +286,70 @@ class JdepsTask {
|
||||
}
|
||||
}
|
||||
},
|
||||
new Option(false, "-q", "-quiet") {
|
||||
void process(JdepsTask task, String opt, String arg) {
|
||||
task.options.nowarning = true;
|
||||
}
|
||||
},
|
||||
new Option(false, "-version", "--version") {
|
||||
void process(JdepsTask task, String opt, String arg) {
|
||||
task.options.version = true;
|
||||
}
|
||||
},
|
||||
|
||||
// ---- module-specific options ----
|
||||
|
||||
new Option(true, "-m", "--module") {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (!task.options.rootModules.isEmpty()) {
|
||||
throw new BadArgs("err.option.already.specified", opt);
|
||||
}
|
||||
task.options.rootModules.add(arg);
|
||||
task.options.addmods.add(arg);
|
||||
}
|
||||
},
|
||||
new Option(true, CommandOption.GENERATE_MODULE_INFO) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.genModuleInfo(Paths.get(arg), false);
|
||||
}
|
||||
},
|
||||
new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.genModuleInfo(Paths.get(arg), true);
|
||||
}
|
||||
},
|
||||
new Option(true, CommandOption.CHECK_MODULES) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
Set<String> mods = Set.of(arg.split(","));
|
||||
task.options.addmods.addAll(mods);
|
||||
task.command = task.checkModuleDeps(mods);
|
||||
}
|
||||
},
|
||||
new Option(false, CommandOption.LIST_DEPS) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.listModuleDeps(false);
|
||||
}
|
||||
},
|
||||
new Option(false, CommandOption.LIST_REDUCED_DEPS) {
|
||||
void process(JdepsTask task, String opt, String arg) throws BadArgs {
|
||||
if (task.command != null) {
|
||||
throw new BadArgs("err.command.set", task.command, opt);
|
||||
}
|
||||
task.command = task.listModuleDeps(true);
|
||||
}
|
||||
},
|
||||
|
||||
// ---- Target filtering options ----
|
||||
new Option(true, "-p", "-package", "--package") {
|
||||
@ -424,17 +436,6 @@ class JdepsTask {
|
||||
}
|
||||
},
|
||||
|
||||
new Option(false, "-q", "-quiet") {
|
||||
void process(JdepsTask task, String opt, String arg) {
|
||||
task.options.nowarning = true;
|
||||
}
|
||||
},
|
||||
|
||||
new Option(false, "-version", "--version") {
|
||||
void process(JdepsTask task, String opt, String arg) {
|
||||
task.options.version = true;
|
||||
}
|
||||
},
|
||||
new HiddenOption(false, "-fullversion") {
|
||||
void process(JdepsTask task, String opt, String arg) {
|
||||
task.options.fullVersion = true;
|
||||
|
@ -86,10 +86,6 @@ main.opt.add-modules=\
|
||||
\ --add-modules <module-name>[,<module-name>...]\n\
|
||||
\ Adds modules to the root set for analysis
|
||||
|
||||
main.opt.m=\
|
||||
\ -m <module-name>\n\
|
||||
\ --module <module-name> Specify the root module for analysis
|
||||
|
||||
main.opt.R=\
|
||||
\ -R -recursive Recursively traverse all run-time dependences.\n\
|
||||
\ The -R option implies -filter:none. If -p,\n\
|
||||
@ -121,6 +117,11 @@ main.opt.apionly=\
|
||||
\ type, method parameter types, returned type,\n\
|
||||
\ checked exception types etc.
|
||||
|
||||
main.opt.m=\n\
|
||||
\Module dependence analysis options:\n\
|
||||
\ -m <module-name>\n\
|
||||
\ --module <module-name> Specify the root module for analysis
|
||||
|
||||
main.opt.generate-module-info=\
|
||||
\ --generate-module-info <dir> Generate module-info.java under the specified\n\
|
||||
\ directory. The specified JAR files will be\n\
|
||||
@ -142,7 +143,6 @@ main.opt.check=\
|
||||
\ graph after transition reduction. It also\n\
|
||||
\ identifies any unused qualified exports.
|
||||
|
||||
|
||||
main.opt.dotoutput=\
|
||||
\ -dotoutput <dir>\n\
|
||||
\ --dot-output <dir> Destination directory for DOT file output
|
||||
@ -157,15 +157,15 @@ main.opt.jdkinternals=\
|
||||
\ WARNING: JDK internal APIs are inaccessible.
|
||||
|
||||
main.opt.list-deps=\
|
||||
\ --list-deps Lists the dependences and use of JDK internal\n\
|
||||
\ APIs.
|
||||
\ --list-deps Lists the module dependences and also the\n\
|
||||
\ package names of JDK internal APIs if referenced.
|
||||
|
||||
main.opt.list-reduced-deps=\
|
||||
\ --list-reduced-deps Same as --list-deps with not listing\n\
|
||||
\ the implied reads edges from the module graph\n\
|
||||
\ If module M1 depends on M2 and M3,\n\
|
||||
\ M2 requires public on M3, then M1 reading M3 is\n\
|
||||
\ implied and removed from the module graph.
|
||||
\ If module M1 reads M2, and M2 requires\n\
|
||||
\ transitive on M3, then M1 reading M3 is implied\n\
|
||||
\ and is not shown in the graph.
|
||||
|
||||
main.opt.depth=\
|
||||
\ -depth=<depth> Specify the depth of the transitive\n\
|
||||
|
@ -40,6 +40,7 @@ import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.ModifiersTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
@ -59,6 +60,7 @@ import jdk.jshell.TaskFactory.AnalyzeTask;
|
||||
import jdk.jshell.TaskFactory.BaseTask;
|
||||
import jdk.jshell.TaskFactory.CompileTask;
|
||||
import jdk.jshell.TaskFactory.ParseTask;
|
||||
import jdk.jshell.Wrap.CompoundWrap;
|
||||
import jdk.jshell.Wrap.Range;
|
||||
import jdk.jshell.Snippet.Status;
|
||||
import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
|
||||
@ -274,26 +276,119 @@ class Eval {
|
||||
for (Tree unitTree : units) {
|
||||
VariableTree vt = (VariableTree) unitTree;
|
||||
String name = vt.getName().toString();
|
||||
String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
|
||||
Tree baseType = vt.getType();
|
||||
String typeName;
|
||||
String fullTypeName;
|
||||
TreeDependencyScanner tds = new TreeDependencyScanner();
|
||||
tds.scan(baseType); // Not dependent on initializer
|
||||
Wrap typeWrap;
|
||||
Wrap anonDeclareWrap = null;
|
||||
Wrap winit = null;
|
||||
StringBuilder sbBrackets = new StringBuilder();
|
||||
while (baseType instanceof ArrayTypeTree) {
|
||||
//TODO handle annotations too
|
||||
baseType = ((ArrayTypeTree) baseType).getType();
|
||||
sbBrackets.append("[]");
|
||||
Tree baseType = vt.getType();
|
||||
if (baseType != null) {
|
||||
tds.scan(baseType); // Not dependent on initializer
|
||||
fullTypeName = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
|
||||
while (baseType instanceof ArrayTypeTree) {
|
||||
//TODO handle annotations too
|
||||
baseType = ((ArrayTypeTree) baseType).getType();
|
||||
sbBrackets.append("[]");
|
||||
}
|
||||
Range rtype = dis.treeToRange(baseType);
|
||||
typeWrap = Wrap.rangeWrap(compileSource, rtype);
|
||||
} else {
|
||||
Tree init = vt.getInitializer();
|
||||
if (init != null) {
|
||||
Range rinit = dis.treeToRange(init);
|
||||
String initCode = rinit.part(compileSource);
|
||||
ExpressionInfo ei =
|
||||
ExpressionToTypeInfo.localVariableTypeForInitializer(initCode, state);
|
||||
typeName = ei == null ? "java.lang.Object" : ei.typeName;
|
||||
fullTypeName = ei == null ? "java.lang.Object" : ei.fullTypeName;
|
||||
if (ei != null && init.getKind() == Tree.Kind.NEW_CLASS &&
|
||||
((NewClassTree) init).getClassBody() != null) {
|
||||
NewClassTree nct = (NewClassTree) init;
|
||||
StringBuilder constructor = new StringBuilder();
|
||||
constructor.append(fullTypeName).append("(");
|
||||
String sep = "";
|
||||
if (ei.enclosingInstanceType != null) {
|
||||
constructor.append(ei.enclosingInstanceType);
|
||||
constructor.append(" encl");
|
||||
sep = ", ";
|
||||
}
|
||||
int idx = 0;
|
||||
for (String type : ei.parameterTypes) {
|
||||
constructor.append(sep);
|
||||
constructor.append(type);
|
||||
constructor.append(" ");
|
||||
constructor.append("arg" + idx++);
|
||||
sep = ", ";
|
||||
}
|
||||
if (ei.enclosingInstanceType != null) {
|
||||
constructor.append(") { encl.super (");
|
||||
} else {
|
||||
constructor.append(") { super (");
|
||||
}
|
||||
sep = "";
|
||||
for (int i = 0; i < idx; i++) {
|
||||
constructor.append(sep);
|
||||
constructor.append("arg" + i++);
|
||||
sep = ", ";
|
||||
}
|
||||
constructor.append("); }");
|
||||
List<? extends Tree> members = nct.getClassBody().getMembers();
|
||||
Range bodyRange = dis.treeListToRange(members);
|
||||
Wrap bodyWrap;
|
||||
|
||||
if (bodyRange != null) {
|
||||
bodyWrap = Wrap.rangeWrap(compileSource, bodyRange);
|
||||
} else {
|
||||
bodyWrap = Wrap.simpleWrap(" ");
|
||||
}
|
||||
|
||||
Range argRange = dis.treeListToRange(nct.getArguments());
|
||||
Wrap argWrap;
|
||||
|
||||
if (argRange != null) {
|
||||
argWrap = Wrap.rangeWrap(compileSource, argRange);
|
||||
} else {
|
||||
argWrap = Wrap.simpleWrap(" ");
|
||||
}
|
||||
|
||||
if (ei.enclosingInstanceType != null) {
|
||||
Range enclosingRanges =
|
||||
dis.treeToRange(nct.getEnclosingExpression());
|
||||
Wrap enclosingWrap = Wrap.rangeWrap(compileSource, enclosingRanges);
|
||||
argWrap = argRange != null ? new CompoundWrap(enclosingWrap,
|
||||
Wrap.simpleWrap(","),
|
||||
argWrap)
|
||||
: enclosingWrap;
|
||||
}
|
||||
Wrap hwrap = Wrap.simpleWrap("public static class " + fullTypeName +
|
||||
(ei.isClass ? " extends " : " implements ") +
|
||||
typeName + " { " + constructor);
|
||||
anonDeclareWrap = new CompoundWrap(hwrap, bodyWrap, Wrap.simpleWrap("}"));
|
||||
winit = new CompoundWrap("new " + fullTypeName + "(", argWrap, ")");
|
||||
|
||||
String superType = typeName;
|
||||
|
||||
typeName = fullTypeName;
|
||||
fullTypeName = ei.isClass ? "<anonymous class extending " + superType + ">"
|
||||
: "<anonymous class implementing " + superType + ">";
|
||||
}
|
||||
tds.scan(init);
|
||||
} else {
|
||||
fullTypeName = typeName = "java.lang.Object";
|
||||
}
|
||||
typeWrap = Wrap.identityWrap(typeName);
|
||||
}
|
||||
Range rtype = dis.treeToRange(baseType);
|
||||
Range runit = dis.treeToRange(vt);
|
||||
runit = new Range(runit.begin, runit.end - 1);
|
||||
ExpressionTree it = vt.getInitializer();
|
||||
Range rinit = null;
|
||||
int nameMax = runit.end - 1;
|
||||
SubKind subkind;
|
||||
if (it != null) {
|
||||
subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
|
||||
rinit = dis.treeToRange(it);
|
||||
Range rinit = dis.treeToRange(it);
|
||||
winit = winit == null ? Wrap.rangeWrap(compileSource, rinit) : winit;
|
||||
nameMax = rinit.begin - 1;
|
||||
} else {
|
||||
subkind = SubKind.VAR_DECLARATION_SUBKIND;
|
||||
@ -304,10 +399,11 @@ class Eval {
|
||||
}
|
||||
int nameEnd = nameStart + name.length();
|
||||
Range rname = new Range(nameStart, nameEnd);
|
||||
Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
|
||||
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
|
||||
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
|
||||
winit, anonDeclareWrap);
|
||||
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
|
||||
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
|
||||
name, subkind, typeName,
|
||||
name, subkind, fullTypeName,
|
||||
tds.declareReferences(), modDiag);
|
||||
snippets.add(snip);
|
||||
}
|
||||
|
@ -29,14 +29,20 @@ import com.sun.source.tree.ReturnTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.ConditionalExpressionTree;
|
||||
import com.sun.source.tree.ExpressionStatementTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import jdk.jshell.TaskFactory.AnalyzeTask;
|
||||
|
||||
/**
|
||||
@ -63,6 +69,10 @@ class ExpressionToTypeInfo {
|
||||
public static class ExpressionInfo {
|
||||
ExpressionTree tree;
|
||||
String typeName;
|
||||
String fullTypeName;
|
||||
List<String> parameterTypes;
|
||||
String enclosingInstanceType;
|
||||
boolean isClass;
|
||||
boolean isNonVoid;
|
||||
}
|
||||
|
||||
@ -111,6 +121,16 @@ class ExpressionToTypeInfo {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
|
||||
if (isTargetContext) {
|
||||
throw new Result(getCurrentPath());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Type pathToType(TreePath tp) {
|
||||
@ -156,6 +176,30 @@ class ExpressionToTypeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry method: get expression info corresponding to a local variable declaration if its type
|
||||
* has been inferred automatically from the given initializer.
|
||||
* @param code the initializer as a string
|
||||
* @param state a JShell instance
|
||||
* @return type information
|
||||
*/
|
||||
public static ExpressionInfo localVariableTypeForInitializer(String code, JShell state) {
|
||||
if (code == null || code.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodWrap("var $$$ = " + code));
|
||||
AnalyzeTask at = state.taskFactory.new AnalyzeTask(codeWrap);
|
||||
CompilationUnitTree cu = at.firstCuTree();
|
||||
if (at.hasErrors() || cu == null) {
|
||||
return null;
|
||||
}
|
||||
return new ExpressionToTypeInfo(at, cu, state).typeOfExpression();
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ExpressionInfo typeOfExpression() {
|
||||
return treeToInfo(findExpressionPath());
|
||||
}
|
||||
@ -172,9 +216,11 @@ class ExpressionToTypeInfo {
|
||||
private ExpressionInfo treeToInfo(TreePath tp) {
|
||||
if (tp != null) {
|
||||
Tree tree = tp.getLeaf();
|
||||
if (tree instanceof ExpressionTree) {
|
||||
boolean isExpression = tree instanceof ExpressionTree;
|
||||
if (isExpression || tree.getKind() == Kind.VARIABLE) {
|
||||
ExpressionInfo ei = new ExpressionInfo();
|
||||
ei.tree = (ExpressionTree) tree;
|
||||
if (isExpression)
|
||||
ei.tree = (ExpressionTree) tree;
|
||||
Type type = pathToType(tp, tree);
|
||||
if (type != null) {
|
||||
switch (type.getKind()) {
|
||||
@ -189,27 +235,56 @@ class ExpressionToTypeInfo {
|
||||
break;
|
||||
default: {
|
||||
ei.isNonVoid = true;
|
||||
ei.typeName = varTypeName(type);
|
||||
if (ei.typeName == null) {
|
||||
ei.typeName = OBJECT_TYPE_NAME;
|
||||
}
|
||||
ei.typeName = varTypeName(type, false);
|
||||
ei.fullTypeName = varTypeName(type, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tree.getKind() == Tree.Kind.VARIABLE) {
|
||||
Tree init = ((VariableTree) tree).getInitializer();
|
||||
if (init.getKind() == Tree.Kind.NEW_CLASS &&
|
||||
((NewClassTree) init).getClassBody() != null) {
|
||||
NewClassTree nct = (NewClassTree) init;
|
||||
ClassTree clazz = nct.getClassBody();
|
||||
MethodTree constructor = (MethodTree) clazz.getMembers().get(0);
|
||||
ExpressionStatementTree superCallStatement =
|
||||
(ExpressionStatementTree) constructor.getBody().getStatements().get(0);
|
||||
MethodInvocationTree superCall =
|
||||
(MethodInvocationTree) superCallStatement.getExpression();
|
||||
TreePath superCallPath =
|
||||
at.trees().getPath(tp.getCompilationUnit(), superCall.getMethodSelect());
|
||||
Type constrType = pathToType(superCallPath);
|
||||
ei.parameterTypes = constrType.getParameterTypes()
|
||||
.stream()
|
||||
.map(t -> varTypeName(t, false))
|
||||
.collect(List.collector());
|
||||
if (nct.getEnclosingExpression() != null) {
|
||||
TreePath enclPath = new TreePath(tp, nct.getEnclosingExpression());
|
||||
ei.enclosingInstanceType = varTypeName(pathToType(enclPath), false);
|
||||
}
|
||||
ei.isClass = at.task.getTypes().directSupertypes(type).size() == 1;
|
||||
}
|
||||
}
|
||||
return ei;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String varTypeName(Type type) {
|
||||
private String varTypeName(Type type, boolean printIntersectionTypes) {
|
||||
try {
|
||||
TypePrinter tp = new VarTypePrinter(at.messages(),
|
||||
state.maps::fullClassNameAndPackageToClass, syms, types);
|
||||
return tp.toString(type);
|
||||
TypePrinter tp = new TypePrinter(at.messages(),
|
||||
state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
|
||||
List<Type> captures = types.captures(type);
|
||||
String res = tp.toString(types.upward(type, captures));
|
||||
|
||||
if (res == null)
|
||||
res = OBJECT_TYPE_NAME;
|
||||
|
||||
return res;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
return OBJECT_TYPE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ class ReplParser extends JavacParser {
|
||||
//mods.flags |= Flags.STATIC;
|
||||
List<JCTree> defs
|
||||
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
|
||||
new ListBuffer<JCTree>()).toList();
|
||||
new ListBuffer<JCTree>(), true).toList();
|
||||
accept(SEMI);
|
||||
storeEnd(defs.last(), S.prevToken().endPos);
|
||||
return defs;
|
||||
|
@ -134,6 +134,8 @@ import static jdk.jshell.TreeDissector.printType;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import javax.lang.model.type.IntersectionType;
|
||||
|
||||
/**
|
||||
* The concrete implementation of SourceCodeAnalysis.
|
||||
* @author Robert Field
|
||||
@ -715,6 +717,13 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
|
||||
return Collections.emptyList();
|
||||
|
||||
switch (site.getKind()) {
|
||||
case INTERSECTION: {
|
||||
List<Element> result = new ArrayList<>();
|
||||
for (TypeMirror bound : ((IntersectionType) site).getBounds()) {
|
||||
result.addAll(membersOf(at, bound, shouldGenerateDotClassItem));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case DECLARED: {
|
||||
TypeElement element = (TypeElement) at.getTypes().asElement(site);
|
||||
List<Element> result = new ArrayList<>();
|
||||
|
@ -61,7 +61,20 @@ import javax.lang.model.util.Elements;
|
||||
import javax.tools.FileObject;
|
||||
import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
|
||||
import java.lang.Runtime.Version;
|
||||
import java.nio.CharBuffer;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.tools.javac.code.Kinds;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import com.sun.tools.javac.parser.Parser;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
|
||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
import com.sun.tools.javac.util.Context.Factory;
|
||||
import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
|
||||
import jdk.jshell.Snippet.Status;
|
||||
|
||||
/**
|
||||
* The primary interface to the compiler API. Parsing, analysis, and
|
||||
@ -355,6 +368,7 @@ class TaskFactory {
|
||||
Iterable<? extends JavaFileObject> compilationUnits = inputs
|
||||
.map(in -> sh.sourceToFileObject(fileManager, in))
|
||||
.collect(Collectors.toList());
|
||||
JShellJavaCompiler.preRegister(context, state);
|
||||
this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
|
||||
fileManager, diagnostics, options, null,
|
||||
compilationUnits, context);
|
||||
@ -464,4 +478,57 @@ class TaskFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JShellJavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
|
||||
|
||||
public static void preRegister(Context c, JShell state) {
|
||||
c.put(compilerKey, (Factory<com.sun.tools.javac.main.JavaCompiler>) i -> new JShellJavaCompiler(i, state));
|
||||
}
|
||||
|
||||
private final JShell state;
|
||||
|
||||
public JShellJavaCompiler(Context context, JShell state) {
|
||||
super(context);
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAnnotations(com.sun.tools.javac.util.List<JCCompilationUnit> roots, Collection<String> classnames) {
|
||||
super.processAnnotations(roots, classnames);
|
||||
state.maps
|
||||
.snippetList()
|
||||
.stream()
|
||||
.filter(s -> s.status() == Status.VALID)
|
||||
.filter(s -> s.kind() == Snippet.Kind.VAR)
|
||||
.filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)
|
||||
.forEach(s -> setVariableType(roots, (VarSnippet) s));
|
||||
}
|
||||
|
||||
private void setVariableType(com.sun.tools.javac.util.List<JCCompilationUnit> roots, VarSnippet s) {
|
||||
ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
|
||||
if (clazz == null || !clazz.isCompleted())
|
||||
return;
|
||||
VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
|
||||
if (field != null) {
|
||||
JavaFileObject prev = log.useSource(null);
|
||||
DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
|
||||
try {
|
||||
String typeName = s.typeName();
|
||||
CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
|
||||
Parser parser = parserFactory.newParser(buf, false, false, false);
|
||||
JCExpression expr = parser.parseExpression();
|
||||
if (expr.hasTag(Tag.TYPECAST)) {
|
||||
JCTypeCast tree = (JCTypeCast) expr;
|
||||
if (tree.clazz.hasTag(Tag.TYPEINTERSECTION)) {
|
||||
field.type = attr.attribType(tree.clazz,
|
||||
((JCClassDecl) roots.head.getTypeDecls().head).sym);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
log.popDiagnosticHandler(h);
|
||||
log.useSource(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ class TreeDissector {
|
||||
Type typeImpl = (Type) type;
|
||||
try {
|
||||
TypePrinter tp = new TypePrinter(at.messages(),
|
||||
state.maps::fullClassNameAndPackageToClass);
|
||||
state.maps::fullClassNameAndPackageToClass, true);
|
||||
return tp.toString(typeImpl);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
|
@ -32,9 +32,11 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
import com.sun.tools.javac.code.Type.IntersectionClassType;
|
||||
import com.sun.tools.javac.util.JavacMessages;
|
||||
import java.util.Locale;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Print types in source form.
|
||||
@ -45,10 +47,14 @@ class TypePrinter extends Printer {
|
||||
|
||||
private final JavacMessages messages;
|
||||
private final BinaryOperator<String> fullClassNameAndPackageToClass;
|
||||
private final boolean printEnhancedTypes;
|
||||
|
||||
TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
|
||||
TypePrinter(JavacMessages messages,
|
||||
BinaryOperator<String> fullClassNameAndPackageToClass,
|
||||
boolean printEnhancedTypes) {
|
||||
this.messages = messages;
|
||||
this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
|
||||
this.printEnhancedTypes = printEnhancedTypes;
|
||||
}
|
||||
|
||||
String toString(Type t) {
|
||||
@ -92,8 +98,18 @@ class TypePrinter extends Printer {
|
||||
protected String className(ClassType t, boolean longform, Locale locale) {
|
||||
Symbol sym = t.tsym;
|
||||
if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
|
||||
return OBJECT;
|
||||
if (printEnhancedTypes) {
|
||||
return ((IntersectionClassType) t).getExplicitComponents()
|
||||
.stream()
|
||||
.map(i -> visit(i, locale))
|
||||
.collect(Collectors.joining("&"));
|
||||
} else {
|
||||
return OBJECT;
|
||||
}
|
||||
} else if (sym.name.length() == 0) {
|
||||
if (printEnhancedTypes) {
|
||||
return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
|
||||
}
|
||||
// Anonymous
|
||||
String s;
|
||||
ClassType norm = (ClassType) t.tsym.type;
|
||||
|
@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
package jdk.jshell;
|
||||
|
||||
import java.util.HashSet;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
import com.sun.tools.javac.util.JavacMessages;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.function.BinaryOperator;
|
||||
import com.sun.tools.javac.code.BoundKind;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type.CapturedType;
|
||||
import com.sun.tools.javac.code.Type.StructuralTypeMapping;
|
||||
import com.sun.tools.javac.code.Type.TypeVar;
|
||||
import com.sun.tools.javac.code.Type.WildcardType;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.code.Types.SimpleVisitor;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import static com.sun.tools.javac.code.BoundKind.EXTENDS;
|
||||
import static com.sun.tools.javac.code.BoundKind.SUPER;
|
||||
import static com.sun.tools.javac.code.BoundKind.UNBOUND;
|
||||
import static com.sun.tools.javac.code.Type.ArrayType;
|
||||
import static com.sun.tools.javac.code.TypeTag.BOT;
|
||||
import static com.sun.tools.javac.code.TypeTag.WILDCARD;
|
||||
|
||||
/**
|
||||
* Print variable types in source form.
|
||||
* TypeProjection and CaptureScanner are copied from Types in the JEP-286
|
||||
* Sandbox by Maurizio. The checks for Non-Denotable in TypePrinter are
|
||||
* cribbed from denotableChecker of the same source.
|
||||
*
|
||||
* @author Maurizio Cimadamore
|
||||
* @author Robert Field
|
||||
*/
|
||||
class VarTypePrinter extends TypePrinter {
|
||||
private static final String WILD = "?";
|
||||
|
||||
private final Symtab syms;
|
||||
private final Types types;
|
||||
|
||||
VarTypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass,
|
||||
Symtab syms, Types types) {
|
||||
super(messages, fullClassNameAndPackageToClass);
|
||||
this.syms = syms;
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString(Type t) {
|
||||
return super.toString(upward(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitTypeVar(TypeVar t, Locale locale) {
|
||||
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
|
||||
(i.e cannot have been produced by inference (18.4))
|
||||
*/
|
||||
// and beyond that, there are no global type vars, so if there are any
|
||||
// type variables left, they need to be eliminated
|
||||
return WILD; // Non-denotable
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitCapturedType(CapturedType t, Locale locale) {
|
||||
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
|
||||
(i.e cannot have been produced by capture conversion (5.1.10))
|
||||
*/
|
||||
return WILD; // Non-denotable
|
||||
}
|
||||
|
||||
public Type upward(Type t) {
|
||||
List<Type> captures = captures(t);
|
||||
return upward(t, captures);
|
||||
}
|
||||
|
||||
/************* Following from JEP-286 Types.java ***********/
|
||||
|
||||
public Type upward(Type t, List<Type> vars) {
|
||||
return t.map(new TypeProjection(vars), true);
|
||||
}
|
||||
|
||||
public List<Type> captures(Type t) {
|
||||
CaptureScanner cs = new CaptureScanner();
|
||||
Set<Type> captures = new HashSet<>();
|
||||
cs.visit(t, captures);
|
||||
return List.from(captures);
|
||||
}
|
||||
|
||||
class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
|
||||
|
||||
@Override
|
||||
public Void visitType(Type t, Set<Type> types) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitClassType(ClassType t, Set<Type> seen) {
|
||||
if (t.isCompound()) {
|
||||
types.directSupertypes(t).forEach(s -> visit(s, seen));
|
||||
} else {
|
||||
t.allparams().forEach(ta -> visit(ta, seen));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitArrayType(ArrayType t, Set<Type> seen) {
|
||||
return visit(t.elemtype, seen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitWildcardType(WildcardType t, Set<Type> seen) {
|
||||
visit(t.type, seen);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitTypeVar(TypeVar t, Set<Type> seen) {
|
||||
if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
|
||||
visit(t.getUpperBound(), seen);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCapturedType(CapturedType t, Set<Type> seen) {
|
||||
if (seen.add(t)) {
|
||||
visit(t.getUpperBound(), seen);
|
||||
visit(t.getLowerBound(), seen);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class TypeProjection extends StructuralTypeMapping<Boolean> {
|
||||
|
||||
List<Type> vars;
|
||||
Set<Type> seen = new HashSet<>();
|
||||
|
||||
public TypeProjection(List<Type> vars) {
|
||||
this.vars = vars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitClassType(ClassType t, Boolean upward) {
|
||||
if (upward && !t.isCompound() && t.tsym.name.isEmpty()) {
|
||||
//lift anonymous class type to first supertype (class or interface)
|
||||
return types.directSupertypes(t).last();
|
||||
} else if (t.isCompound()) {
|
||||
List<Type> components = types.directSupertypes(t);
|
||||
List<Type> components1 = components.map(c -> c.map(this, upward));
|
||||
if (components == components1) return t;
|
||||
else return types.makeIntersectionType(components1);
|
||||
} else {
|
||||
Type outer = t.getEnclosingType();
|
||||
Type outer1 = visit(outer, upward);
|
||||
List<Type> typarams = t.getTypeArguments();
|
||||
List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, upward));
|
||||
if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
|
||||
//not defined
|
||||
return syms.botType;
|
||||
}
|
||||
if (outer1 == outer && typarams1 == typarams) return t;
|
||||
else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
|
||||
@Override
|
||||
protected boolean needsStripping() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected Type makeWildcard(Type upper, Type lower) {
|
||||
BoundKind bk;
|
||||
Type bound;
|
||||
if (upper.hasTag(BOT)) {
|
||||
upper = syms.objectType;
|
||||
}
|
||||
boolean isUpperObject = types.isSameType(upper, syms.objectType);
|
||||
if (!lower.hasTag(BOT) && isUpperObject) {
|
||||
bound = lower;
|
||||
bk = SUPER;
|
||||
} else {
|
||||
bound = upper;
|
||||
bk = isUpperObject ? UNBOUND : EXTENDS;
|
||||
}
|
||||
return new WildcardType(bound, bk, syms.boundClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitTypeVar(TypeVar t, Boolean upward) {
|
||||
if (vars.contains(t)) {
|
||||
try {
|
||||
if (seen.add(t)) {
|
||||
return (upward ?
|
||||
t.getUpperBound() :
|
||||
(t.getLowerBound() == null) ?
|
||||
syms.botType :
|
||||
t.getLowerBound())
|
||||
.map(this, upward);
|
||||
} else {
|
||||
//cycle
|
||||
return syms.objectType;
|
||||
}
|
||||
} finally {
|
||||
seen.remove(t);
|
||||
}
|
||||
} else {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitWildcardType(WildcardType wt, Boolean upward) {
|
||||
if (upward) {
|
||||
return wt.isExtendsBound() ?
|
||||
wt.type.map(this, upward) :
|
||||
syms.objectType;
|
||||
} else {
|
||||
return wt.isSuperBound() ?
|
||||
wt.type.map(this, upward) :
|
||||
syms.botType;
|
||||
}
|
||||
}
|
||||
|
||||
private Type mapTypeArgument(Type t, boolean upward) {
|
||||
if (!t.containsAny(vars)) {
|
||||
return t;
|
||||
} else if (!t.hasTag(WILDCARD) && !upward) {
|
||||
//not defined
|
||||
return syms.botType;
|
||||
} else {
|
||||
Type upper = t.map(this, upward);
|
||||
Type lower = t.map(this, !upward);
|
||||
return makeWildcard(upper, lower);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -74,16 +74,15 @@ abstract class Wrap implements GeneralWrap {
|
||||
* @param rdecl Type name and name
|
||||
* @return
|
||||
*/
|
||||
public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
|
||||
public static Wrap varWrap(String source, Wrap wtype, String brackets,
|
||||
Range rname, Wrap winit, Wrap anonDeclareWrap) {
|
||||
RangeWrap wname = new RangeWrap(source, rname);
|
||||
RangeWrap wtype = new RangeWrap(source, rtype);
|
||||
Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
|
||||
Wrap wmeth;
|
||||
|
||||
if (rinit == null) {
|
||||
if (winit == null) {
|
||||
wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n");
|
||||
} else {
|
||||
RangeWrap winit = new RangeWrap(source, rinit);
|
||||
// int x = y
|
||||
// int x_ = y; return x = x_;
|
||||
// decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
|
||||
@ -93,7 +92,8 @@ abstract class Wrap implements GeneralWrap {
|
||||
);
|
||||
}
|
||||
Wrap wInitMeth = new DoitMethodWrap(wmeth);
|
||||
return new CompoundWrap(wVarDecl, wInitMeth);
|
||||
return anonDeclareWrap != null ? new CompoundWrap(wVarDecl, wInitMeth, anonDeclareWrap)
|
||||
: new CompoundWrap(wVarDecl, wInitMeth);
|
||||
}
|
||||
|
||||
public static Wrap tempVarWrap(String source, String typename, String name) {
|
||||
@ -112,6 +112,14 @@ abstract class Wrap implements GeneralWrap {
|
||||
return new NoWrap(source);
|
||||
}
|
||||
|
||||
public static Wrap identityWrap(String source) {
|
||||
return new NoWrap(source);
|
||||
}
|
||||
|
||||
public static Wrap rangeWrap(String source, Range range) {
|
||||
return new RangeWrap(source, range);
|
||||
}
|
||||
|
||||
public static Wrap classMemberWrap(String source) {
|
||||
Wrap w = new NoWrap(source);
|
||||
return new CompoundWrap(" public static\n ", w);
|
||||
|
@ -273,7 +273,8 @@ abstract class CompilationPhase {
|
||||
private static final class LocalVariableTypeCalculationPhase extends CompilationPhase {
|
||||
@Override
|
||||
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
|
||||
final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
|
||||
final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler,
|
||||
compiler.getReturnType()));
|
||||
final ScriptEnvironment senv = compiler.getScriptEnvironment();
|
||||
final PrintWriter err = senv.getErr();
|
||||
|
||||
|
@ -619,6 +619,10 @@ public final class Compiler implements Loggable {
|
||||
return types == null ? null : types.get(fn, pos);
|
||||
}
|
||||
|
||||
Type getReturnType() {
|
||||
return types == null || !isOnDemandCompilation() ? Type.UNKNOWN : types.getReturnType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a compilation job
|
||||
*
|
||||
|
@ -405,10 +405,15 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
|
||||
// variables).
|
||||
private final Deque<Label> catchLabels = new ArrayDeque<>();
|
||||
|
||||
LocalVariableTypesCalculator(final Compiler compiler) {
|
||||
private LocalVariableTypesCalculator(final Compiler compiler) {
|
||||
this.compiler = compiler;
|
||||
}
|
||||
|
||||
LocalVariableTypesCalculator(final Compiler compiler, final Type returnType) {
|
||||
this(compiler);
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
private JumpTarget createJumpTarget(final Label label) {
|
||||
assert !jumpTargets.containsKey(label);
|
||||
final JumpTarget jumpTarget = new JumpTarget();
|
||||
|
@ -117,6 +117,15 @@ public final class TypeMap {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the return type required for the call site we're compiling for. This only determines
|
||||
* whether object return type is required or not.
|
||||
* @return Type.OBJECT for call sites with object return types, Type.UNKNOWN for everything else
|
||||
*/
|
||||
Type getReturnType() {
|
||||
return returnType.isObject() ? Type.OBJECT : Type.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString("");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user