This commit is contained in:
Jesper Wilhelmsson 2017-10-04 20:01:19 +00:00
commit eed5d34c26
235 changed files with 7673 additions and 2642 deletions

View File

@ -449,3 +449,4 @@ a85884d55ce32799f5c7382b7ea4839052b362a2 jdk-10+21
e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22
22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23
3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24
8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25

View File

@ -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

View File

@ -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

View File

@ -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)))

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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@

View File

@ -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 \

View File

@ -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);

View File

@ -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.

View File

@ -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],

View File

@ -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">

View File

@ -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

View File

@ -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

View File

@ -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} \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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) {

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 + "]";
}
}
/**

View File

@ -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;
}

View File

@ -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;

View File

@ -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() +

View File

@ -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>
*

View File

@ -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) {

View File

@ -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) {

View File

@ -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&lt;E&gt; {
* <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();
* }

View File

@ -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

View File

@ -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}.

View File

@ -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) {

View File

@ -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;

View File

@ -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;
};

View File

@ -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) {

View File

@ -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;

View File

@ -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

View File

@ -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();
/**

View File

@ -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

View File

@ -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:

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -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()
};
/**

View File

@ -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)) {

View File

@ -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;

View File

@ -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())) {

View File

@ -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()) {

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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();

View File

@ -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.

View File

@ -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); }

View File

@ -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

View File

@ -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;

View File

@ -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");

View File

@ -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

View File

@ -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(")");
}
/**

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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 {

View File

@ -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()) {

View File

@ -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()) {

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -47,15 +47,16 @@ public enum HtmlStyle {
circle,
classUseContainer,
colConstructorName,
colDeprecatedItemName,
colFirst,
colLast,
colSecond,
constantsSummary,
constantValuesContainer,
contentContainer,
deprecatedContent,
deprecatedLabel,
deprecatedSummary,
deprecationBlock,
deprecationComment,
description,
descfrmTypeLabel,

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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.

View File

@ -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;

View File

@ -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\

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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<>();

View File

@ -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);
}
}
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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);

View File

@ -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();

View File

@ -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
*

View File

@ -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();

View File

@ -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