Merge
This commit is contained in:
commit
fe30b6862a
@ -23,25 +23,46 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
# This is the JDK used to build and run the bootstrap version of javac.
|
||||
# The bootstrap javac is used to compile both boostrap versions of the
|
||||
# other tools, and product versions of all the tools.
|
||||
# Override this path as needed, either on the command line or in
|
||||
# one of the standard user build.properties files (see build.xml)
|
||||
#javac configuration for "normal build" (these will be passed to the bootstrap compiler):
|
||||
javac.debug = true
|
||||
javac.debuglevel = source,lines,vars
|
||||
javac.extra.opts=-XDignore.symbol.file=true
|
||||
javac.includes=
|
||||
javac.lint.opts = -Xlint:all,-deprecation -Werror
|
||||
javac.source = 8
|
||||
javac.target = 8
|
||||
|
||||
# boot.java.home = /opt/jdk/1.7.0
|
||||
boot.java = ${boot.java.home}/bin/java
|
||||
boot.javac = ${boot.java.home}/bin/javac
|
||||
#javac configuration for bootstrap build (these will be passed to the compiler from the given boot JDK):
|
||||
boot.javac.extra.opts=-XDignore.symbol.file=true
|
||||
boot.javac.includes = \
|
||||
javax/annotation/processing/ \
|
||||
javax/lang/model/ \
|
||||
javax/tools/ \
|
||||
jdk/ \
|
||||
com/sun/source/ \
|
||||
com/sun/tools/javac/ \
|
||||
com/sun/tools/doclint/
|
||||
boot.javac.lint.opts=
|
||||
boot.javac.source = 8
|
||||
boot.javac.target = 8
|
||||
|
||||
# This is the JDK used to run the product version of the tools,
|
||||
# for example, for testing. If you're building a complete JDK, specify that.
|
||||
# Override this path as needed, either on the command line or in
|
||||
# one of the standard user build.properties files (see build.xml)
|
||||
#configuration of submodules (share by both the bootstrap and normal compilation):
|
||||
langtools.modules=java.base:java.compiler:jdk.compiler:jdk.dev:jdk.javadoc
|
||||
java.base.dependencies=
|
||||
java.compiler.dependencies=java.base
|
||||
jdk.compiler.dependencies=java.base:java.compiler
|
||||
jdk.javadoc.dependencies=java.base:java.compiler:jdk.compiler
|
||||
jdk.dev.dependencies=java.base:java.compiler:jdk.compiler
|
||||
|
||||
# target.java.home = /opt/jdk/1.8.0
|
||||
target.java = ${target.java.home}/bin/java
|
||||
#test configuration:
|
||||
jtreg.tests=
|
||||
boot.javac.tests = tools/javac
|
||||
crules.tests = ../make/test/crules
|
||||
|
||||
#javadoc configuration
|
||||
javadoc.jls.cite=The Java™ Language Specification
|
||||
javadoc.jls.option=-tag "jls:a:See <cite>${javadoc.jls.cite}</cite>:" \
|
||||
-tag "implNote:a:Implementation Note:"
|
||||
|
||||
# Version info -- override as needed
|
||||
jdk.version = 1.9.0
|
||||
@ -55,146 +76,4 @@ milestone = internal
|
||||
# timestamps
|
||||
# FIXME -- need to include openjdk as needed
|
||||
release = ${jdk.version}-${milestone}
|
||||
bootstrap.release = ${release}_bootstrap
|
||||
full.version = ${release}-${build.number}
|
||||
bootstrap.full.version = ${bootstrap.release}-${build.number}
|
||||
|
||||
# options for the <javac> tasks used to compile the tools
|
||||
javac.source = 8
|
||||
javac.target = 8
|
||||
javac.debug = true
|
||||
javac.debuglevel = source,lines
|
||||
javac.no.jdk.warnings = -XDignore.symbol.file=true
|
||||
# set the following to -version to verify the versions of javac being used
|
||||
javac.version.opt =
|
||||
# in time, there should be no exceptions to -Xlint:all
|
||||
javac.lint.opts = -Xlint:all,-deprecation -Werror
|
||||
|
||||
# options for the <javadoc> task for javac
|
||||
#javadoc.jls3.url=http://java.sun.com/docs/books/jls/
|
||||
#javadoc.jls3.cite=<a href="${javadoc.jls3.url}">The Java Language Specification, Third Edition</a>
|
||||
#javadoc.jls3.option=-tag "jls3:a:See <cite>${javadoc.jls3.cite}</cite>:"
|
||||
|
||||
|
||||
javadoc.jls.cite=The Java™ Language Specification
|
||||
|
||||
javadoc.jls.option=-tag "jls:a:See <cite>${javadoc.jls.cite}</cite>:"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# jtreg, used to run the JDK regression tests
|
||||
# See http://openjdk.java.net/jtreg/
|
||||
# Override this path as needed, either on the command line or in
|
||||
# one of the standard user build.properties files (see build.xml)
|
||||
|
||||
# jtreg.home = /opt/jtreg/4.1
|
||||
|
||||
# findbugs
|
||||
# See http://findbugs.sourceforge.net/
|
||||
# Override this path as needed, either on the command line or in
|
||||
# one of the standard user build.properties files (see build.xml)
|
||||
|
||||
# findbugs.home = /opt/findbugs/1.2.1
|
||||
|
||||
# vizant (graph visualization tool for Ant)
|
||||
# See http://vizant.sourceforge.net/
|
||||
# Override this path as needed, either on the command line or in
|
||||
# one of the standard user build.properties files (see build.xml)
|
||||
|
||||
# vizant.jar = /opt/vizant/0.1.2/vizant-0.1.2.jar
|
||||
# dot = dot
|
||||
|
||||
#------------------------------------------------------------
|
||||
|
||||
# The following properties define the packages for each of the tools.
|
||||
# Syntactically, they should be suitable as arguments for the "includes"
|
||||
# parameter of Ant filesets. In particular, note the trailing '/'.
|
||||
|
||||
javac.includes = \
|
||||
javax/annotation/processing/ \
|
||||
javax/lang/model/ \
|
||||
javax/tools/ \
|
||||
jdk/ \
|
||||
com/sun/source/ \
|
||||
com/sun/tools/javac/ \
|
||||
com/sun/tools/doclint/
|
||||
|
||||
javac.tests = \
|
||||
tools/javac
|
||||
|
||||
#
|
||||
|
||||
javadoc.includes = \
|
||||
com/sun/javadoc/ \
|
||||
com/sun/tools/javadoc/ \
|
||||
com/sun/tools/doclets/
|
||||
|
||||
javadoc.tests = \
|
||||
tools/javadoc/ \
|
||||
com/sun/javadoc/
|
||||
|
||||
#
|
||||
|
||||
javah.includes = \
|
||||
com/sun/tools/javah/
|
||||
|
||||
javah.tests = \
|
||||
tools/javah/
|
||||
|
||||
#
|
||||
|
||||
javap.includes = \
|
||||
com/sun/tools/classfile/ \
|
||||
com/sun/tools/javap/ \
|
||||
com/sun/tools/jdeps/ \
|
||||
sun/tools/javap/
|
||||
|
||||
javap.tests = \
|
||||
tools/javap/
|
||||
|
||||
#
|
||||
|
||||
sjavac.includes = \
|
||||
com/sun/tools/sjavac/
|
||||
|
||||
sjavac.tests = \
|
||||
tools/sjavac
|
||||
|
||||
crules.tests = ../make/test/crules
|
||||
|
||||
#
|
||||
|
||||
# The following files require the latest JDK to be available.
|
||||
# The API can be provided by using a suitable boot.java.home
|
||||
# or by setting import.jdk
|
||||
require.latest.jdk.files = \
|
||||
com/sun/tools/javac/nio/*.java
|
||||
|
||||
# The following files in the import jdk source directory are required
|
||||
# in order to compile the files defined in ${require.latest.jdk.files}
|
||||
#
|
||||
# For NIO, the list of stub files is defined by the contents of the primary
|
||||
# API packages, together with such types that may be required in order to
|
||||
# compile the stubs. Some of these dependencies would go away if the stub
|
||||
# generator were to be improved -- e.g. by removing unnecessary imports.
|
||||
#
|
||||
import.jdk.stub.files = \
|
||||
java/io/File.java \
|
||||
java/nio/file/**.java \
|
||||
java/nio/file/attribute/**.java \
|
||||
java/nio/file/spi/**.java \
|
||||
java/nio/channels/AsynchronousChannel.java \
|
||||
java/nio/channels/AsynchronousFileChannel.java \
|
||||
java/nio/channels/CompletionHandler.java \
|
||||
java/nio/channels/SeekableByteChannel.java
|
||||
|
||||
# The following value is used by the main jtreg target.
|
||||
# An empty value means all tests
|
||||
# Override as desired to run a specific set of tests
|
||||
jtreg.tests =
|
||||
|
||||
# Check style configuration
|
||||
# overridable name and version
|
||||
checkstyle.name.version = checkstyle-5.4
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,10 +2,8 @@
|
||||
<project name="langtools" basedir="..">
|
||||
|
||||
<script language="javascript" classpath=".idea/classes">
|
||||
var ideaListener = project.getBuildListeners().firstElement();
|
||||
var LangtoolsLogger = Java.type("idea.LangtoolsIdeaAntLogger");
|
||||
project.removeBuildListener(ideaListener)
|
||||
project.addBuildListener(new LangtoolsLogger(ideaListener))
|
||||
new LangtoolsLogger(project)
|
||||
</script>
|
||||
|
||||
<import file="../make/build.xml"/>
|
||||
|
@ -26,7 +26,9 @@
|
||||
package idea;
|
||||
|
||||
import org.apache.tools.ant.BuildEvent;
|
||||
import org.apache.tools.ant.BuildListener;
|
||||
import org.apache.tools.ant.DefaultLogger;
|
||||
import org.apache.tools.ant.Project;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Stack;
|
||||
@ -166,21 +168,17 @@ public final class LangtoolsIdeaAntLogger extends DefaultLogger {
|
||||
}
|
||||
},
|
||||
/** build bootstrap tool target - executed when bootstrapping javac */
|
||||
BUILD_BOOTSTRAP_TOOL("build-bootstrap-.*") {
|
||||
BUILD_BOOTSTRAP_JAVAC("build-bootstrap-javac-classes") {
|
||||
@Override
|
||||
String getDisplayMessage(BuildEvent e) {
|
||||
String targetName = e.getTarget().getName();
|
||||
String tool = targetName.split("-")[2];
|
||||
return "Building bootstrap " + tool + "...";
|
||||
return "Building bootstrap javac...";
|
||||
}
|
||||
},
|
||||
/** build classes target - executed when building classes of given tool */
|
||||
BUILD_TOOL("build-classes-.*") {
|
||||
BUILD_ALL_CLASSES("build-all-classes") {
|
||||
@Override
|
||||
String getDisplayMessage(BuildEvent e) {
|
||||
String targetName = e.getTarget().getName();
|
||||
String tool = targetName.split("-")[2];
|
||||
return "Building " + tool + "...";
|
||||
return "Building all classes...";
|
||||
}
|
||||
},
|
||||
/** synthetic target catching any other target not in this list */
|
||||
@ -195,14 +193,14 @@ public final class LangtoolsIdeaAntLogger extends DefaultLogger {
|
||||
}
|
||||
};
|
||||
|
||||
String targetRegex;
|
||||
String targetName;
|
||||
|
||||
Target(String targetRegex) {
|
||||
this.targetRegex = targetRegex;
|
||||
Target(String targetName) {
|
||||
this.targetName = targetName;
|
||||
}
|
||||
|
||||
boolean matches(String msg) {
|
||||
return msg.matches(targetRegex);
|
||||
return msg.equals(targetName);
|
||||
}
|
||||
|
||||
abstract String getDisplayMessage(BuildEvent e);
|
||||
@ -253,8 +251,14 @@ public final class LangtoolsIdeaAntLogger extends DefaultLogger {
|
||||
/** stack of pending tasks */
|
||||
Stack<Task> tasks = new Stack<>();
|
||||
|
||||
public LangtoolsIdeaAntLogger(DefaultLogger logger) {
|
||||
this.logger = logger;
|
||||
public LangtoolsIdeaAntLogger(Project project) {
|
||||
for (Object o : project.getBuildListeners()) {
|
||||
if (o instanceof DefaultLogger) {
|
||||
this.logger = (DefaultLogger)o;
|
||||
project.removeBuildListener((BuildListener)o);
|
||||
project.addBuildListener(this);
|
||||
}
|
||||
}
|
||||
tasks.push(Task.ROOT);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
<!-- standard tools -->
|
||||
<configuration default="false" name="javac" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="com.sun.tools.javac.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/classes" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/java.compiler/classes:build/jdk.compiler/classes:build/java.base/classes:build/jdk.javadoc/classes:build/jdk.dev/classes" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
@ -24,12 +24,12 @@
|
||||
<ConfigurationWrapper RunnerId="Run" />
|
||||
<method>
|
||||
<option name="Make" enabled="false" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-classes-javac" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="false" name="javadoc" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="com.sun.tools.javadoc.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/classes" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/java.compiler/classes:build/jdk.compiler/classes:build/java.base/classes:build/jdk.javadoc/classes:build/jdk.dev/classes" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
@ -43,12 +43,12 @@
|
||||
<ConfigurationWrapper RunnerId="Run" />
|
||||
<method>
|
||||
<option name="Make" enabled="false" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-classes-javadoc" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="false" name="javap" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="com.sun.tools.javap.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/classes" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/java.compiler/classes:build/jdk.compiler/classes:build/java.base/classes:build/jdk.javadoc/classes:build/jdk.dev/classes" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
@ -62,12 +62,12 @@
|
||||
<ConfigurationWrapper RunnerId="Run" />
|
||||
<method>
|
||||
<option name="Make" enabled="false" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-classes-javap" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="false" name="javah" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="com.sun.tools.javah.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/classes" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/java.compiler/classes:build/jdk.compiler/classes:build/java.base/classes:build/jdk.javadoc/classes:build/jdk.dev/classes" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
@ -81,12 +81,12 @@
|
||||
<ConfigurationWrapper RunnerId="Run" />
|
||||
<method>
|
||||
<option name="Make" enabled="false" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-classes-javah" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="false" name="sjavac" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="com.sun.tools.sjavac.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/classes" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/java.compiler/classes:build/jdk.compiler/classes:build/java.base/classes:build/jdk.javadoc/classes:build/jdk.dev/classes" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
@ -100,13 +100,13 @@
|
||||
<ConfigurationWrapper RunnerId="Run" />
|
||||
<method>
|
||||
<option name="Make" enabled="false" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-classes-sjavac" />
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
|
||||
</method>
|
||||
</configuration>
|
||||
<!-- bootstrap javac -->
|
||||
<configuration default="false" name="javac (bootstrap)" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="com.sun.tools.javac.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/bootstrap/classes" />
|
||||
<option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/bootstrap/java.compiler/classes:build/bootstrap/jdk.compiler/classes:build/bootstrap/java.base/classes:build/bootstrap/jdk.javadoc/classes:build/bootstrap/jdk.dev/classes" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
|
@ -43,10 +43,9 @@ mylib="$mydir/../lib"
|
||||
# dependent jar files for additional dependencies.
|
||||
|
||||
if [ "$LANGTOOLS_USE_BOOTCLASSPATH" != "no" ]; then
|
||||
cp=`unzip -c "$mylib/#PROGRAM#.jar" META-INF/MANIFEST.MF |
|
||||
grep "Class-Path:" |
|
||||
sed -e 's|Class-Path: *||' -e 's|\([a-z]*\.jar\) *|'"$mylib"'/\1#PS#|g'`
|
||||
bcp="$mylib/#PROGRAM#.jar#PS#$cp"
|
||||
cp=`echo "$mylib"/*.jar |
|
||||
sed -e 's|\([a-z.]*\.jar\) *|\1#PS#|g'`
|
||||
bcp=$cp
|
||||
fi
|
||||
|
||||
# tools currently assumes that assertions are enabled in the launcher
|
||||
@ -72,4 +71,4 @@ done
|
||||
unset DUALCASE
|
||||
|
||||
IFS=$nl
|
||||
"#TARGET_JAVA#" "${bcp:+-Xbootclasspath/p:"$bcp"}" ${ea} ${javaOpts} -jar "${mylib}/#PROGRAM#.jar" ${toolOpts}
|
||||
"#TARGET_JAVA#" "${bcp:+-Xbootclasspath/p:"$bcp"}" ${ea} ${javaOpts} com.sun.tools.#PROGRAM#.Main ${toolOpts}
|
||||
|
@ -46,48 +46,34 @@
|
||||
-->
|
||||
<import file="../../build.xml"/>
|
||||
|
||||
<!-- Build project. (action: build; F11)
|
||||
If langtools.tool.name is set, then just build that tool; otherwise
|
||||
build all tools.
|
||||
-->
|
||||
<!-- Build project. (action: build; F11) -->
|
||||
|
||||
<target name="build" depends="-get-tool-if-set,-build-tool,-build-all"
|
||||
description="Build one or all langtools tools"
|
||||
/>
|
||||
|
||||
<condition property="use_bootstrap" value="bootstrap-" else="">
|
||||
<isset property="langtools.tool.bootstrap"/>
|
||||
</condition>
|
||||
<condition property="with_bootclasspath" value="${build.bootstrap.dir}/classes" else="${build.classes.dir}">
|
||||
<isset property="langtools.tool.bootstrap"/>
|
||||
</condition>
|
||||
|
||||
<target name="-build-tool" if="langtools.tool.name">
|
||||
<echo level="info" message="Building ${use_bootstrap}${langtools.tool.name}"/>
|
||||
<echo level="verbose" message="(Unset langtools.tool.name to build all tools)"/>
|
||||
<antcall target="build-${use_bootstrap}${langtools.tool.name}"/>
|
||||
<target name="build" depends="-get-tool-if-set,-build-bootstrap-javac,-build-all" />
|
||||
<target name="-build-bootstrap-javac" if="langtools.tool.bootstrap">
|
||||
<antcall target="build-bootstrap-javac"/>
|
||||
</target>
|
||||
|
||||
<target name="-build-all" unless="langtools.tool.name">
|
||||
<echo level="info" message="Building all tools"/>
|
||||
<echo level="verbose" message="(Set langtools.tool.name to build a single tool)"/>
|
||||
<target name="-build-all" unless="langtools.tool.bootstrap">
|
||||
<antcall target="build-all-tools"/>
|
||||
</target>
|
||||
|
||||
<!-- Compile a single file. (action: compile.single; F9) -->
|
||||
|
||||
<target name="compile-single" depends="build-bootstrap-javac">
|
||||
<target name="compile-single" depends="-get-tool-if-set,build-bootstrap-javac-classes" unless="langtools.tool.bootstrap">
|
||||
<fail unless="includes">Must set property 'includes'</fail>
|
||||
<javac fork="true" executable="${build.bootstrap.dir}/bin/javac"
|
||||
srcdir="${srcdir}"
|
||||
destdir="${build.classes.dir}"
|
||||
<mkdir dir="${build.dir}/${module.name}/classes" />
|
||||
<javac fork="true" executable="${boot.java.home}/bin/javac"
|
||||
srcdir="${basedir}/src/${module.name}/share/classes"
|
||||
destdir="${build.dir}/${module.name}/classes"
|
||||
includes="${includes}"
|
||||
sourcepath=""
|
||||
classpath="${langtools.classes}"
|
||||
includeAntRuntime="no"
|
||||
source="${javac.source}"
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
debuglevel="${javac.debuglevel}"/>
|
||||
debuglevel="${javac.debuglevel}">
|
||||
<compilerarg value="-J-Xbootclasspath/p:${build.bootstrap.dir}/classes"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- Run tool. (action: run; F6)
|
||||
@ -95,16 +81,24 @@
|
||||
the user.
|
||||
-->
|
||||
|
||||
<target name="run" depends="-check-target.java.home,build,-def-run,-get-tool-and-args"
|
||||
<target name="run" depends="-check-target.java.home,-build-classes,-def-run,-get-tool-and-args,-setup-bootclasspath"
|
||||
description="run tool">
|
||||
<echo level="info" message="${with_bootclasspath}"/>
|
||||
<echo level="info" message="Run ${use_bootstrap}${langtools.tool.name} with args ${langtools.tool.args}"/>
|
||||
<run bcp="${with_bootclasspath}" mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}"/>
|
||||
</target>
|
||||
|
||||
<target name="-build-classes" depends="-get-tool-if-set,-build-classes-bootstrap-javac,-build-classes-all" />
|
||||
<target name="-build-classes-bootstrap-javac" if="langtools.tool.bootstrap">
|
||||
<antcall target="build-bootstrap-javac-classes"/>
|
||||
</target>
|
||||
<target name="-build-classes-all" unless="langtools.tool.bootstrap">
|
||||
<antcall target="build-all-classes"/>
|
||||
</target>
|
||||
|
||||
<!-- Run a selected class. (action: run.single; shift-F6) -->
|
||||
|
||||
<target name="run-single" depends="-check-target.java.home,-def-run">
|
||||
<target name="run-single" depends="-check-target.java.home,-setup-bootclasspath,-def-run">
|
||||
<fail unless="run.classname">Must set property 'run.classname' </fail>
|
||||
<echo level="info" message="run ${run.classname}"/>
|
||||
<run mainclass="${run.classname}" args=""/>
|
||||
@ -115,22 +109,22 @@
|
||||
test all tools.
|
||||
-->
|
||||
|
||||
<target name="jtreg" depends="-get-tool-if-set,-jtreg-tool,-jtreg-all"
|
||||
description="Test one or all langtools tools"
|
||||
<target name="jtreg" depends="-get-tool-if-set,-jtreg-bootstrap-javac,-jtreg-all"
|
||||
description="Test langtools tools or bootstrap javac"
|
||||
/>
|
||||
|
||||
<target name="-jtreg-tool" if="langtools.tool.name">
|
||||
<echo level="info" message="Testing ${langtools.tool.name}"/>
|
||||
<echo level="verbose" message="(Unset langtools.tool.name to test all tools)"/>
|
||||
<target name="-jtreg-bootstrap-javac" if="langtools.tool.bootstrap">
|
||||
<echo level="info" message="Testing bootstrap javac"/>
|
||||
<echo level="verbose" message="(Unset langtools.tool.bootstrap to test all tools)"/>
|
||||
<antcall>
|
||||
<target name="jtreg-${langtools.tool.name}"/>
|
||||
<target name="jtreg-bootstrap-javac"/>
|
||||
<target name="-show-jtreg"/>
|
||||
</antcall>
|
||||
</target>
|
||||
|
||||
<target name="-jtreg-all" unless="langtools.tool.name">
|
||||
<target name="-jtreg-all" unless="langtools.tool.bootstrap">
|
||||
<echo level="info" message="Testing all tools"/>
|
||||
<echo level="verbose" message="(Set langtools.tool.name to test a single tool)"/>
|
||||
<echo level="verbose" message="(Set langtools.tool.bootstrap to test bootstrap javac)"/>
|
||||
<antcall>
|
||||
<target name="langtools.jtreg"/>
|
||||
<target name="-show-jtreg"/>
|
||||
@ -165,7 +159,7 @@
|
||||
|
||||
<!-- Debug tool in NetBeans. -->
|
||||
|
||||
<target name="debug" depends="-check-target.java.home,-def-run,-def-start-debugger,-get-tool-and-args,build" if="netbeans.home">
|
||||
<target name="debug" depends="-check-target.java.home,-def-run,-def-start-debugger,-get-tool-and-args,-setup-bootclasspath,-build-classes" if="netbeans.home">
|
||||
<echo level="info" message="Debug ${use_bootstrap}${langtools.tool.name} with args ${langtools.tool.args}"/>
|
||||
<start-debugger/>
|
||||
<run bcp="${with_bootclasspath}" mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}" jpda.jvmargs="${jpda.jvmargs}"/>
|
||||
@ -179,20 +173,29 @@
|
||||
</target>
|
||||
|
||||
<!-- Debug a jtreg test. -->
|
||||
<target name="debug-jtreg" depends="-check-target.java.home,-def-start-debugger,-def-jtreg">
|
||||
<target name="debug-jtreg" depends="-check-target.java.home,-def-start-debugger,-def-jtreg,-get-tool-if-set,-setup-bootclasspath">
|
||||
<fail unless="jtreg.tests">Must set property 'jtreg.tests'</fail>
|
||||
<start-debugger/>
|
||||
<jtreg-tool name="debug" samevm="false" tests="${jtreg.tests}" jpda.jvmargs="${jpda.jvmargs}"/>
|
||||
<jtreg-tool name="debug"
|
||||
samevm="false"
|
||||
tests="${jtreg.tests}"
|
||||
jpda.jvmargs="${jpda.jvmargs}"
|
||||
langtools.classes="${with_bootclasspath}"/>
|
||||
</target>
|
||||
|
||||
<!-- Update a class being debugged. -->
|
||||
|
||||
<target name="debug-fix">
|
||||
<target name="debug-fix" depends="-get-tool-if-set">
|
||||
<fail unless="class">Must set property 'class'
|
||||
</fail>
|
||||
<antcall target="compile-single">
|
||||
<param name="includes" value="${class}.java"/>
|
||||
</antcall>
|
||||
<condition property="build.classes.dir"
|
||||
value="${build.dir}/${module.name}/classes"
|
||||
else="${boot.build.dir}/${module.name}/classes">
|
||||
<isset property="use_bootstrap"/>
|
||||
</condition>
|
||||
<nbjpdareload>
|
||||
<fileset dir="${build.classes.dir}">
|
||||
<include name="${class}.class"/>
|
||||
@ -205,31 +208,10 @@
|
||||
test all tools.
|
||||
-->
|
||||
|
||||
<target name="javadoc" depends="-javadoc-tool,-javadoc-all"
|
||||
description="Generate javadoc for one or all langtools tools"
|
||||
/>
|
||||
|
||||
<target name="-javadoc-tool" if="langtools.tool.name">
|
||||
<echo level="info" message="Generate javadoc for ${langtools.tool.name}"/>
|
||||
<echo level="verbose" message="(Unset langtools.tool.name to generate javadoc for all tools)"/>
|
||||
<antcall>
|
||||
<target name="javadoc-${langtools.tool.name}"/>
|
||||
<target name="-show-javadoc"/>
|
||||
</antcall>
|
||||
</target>
|
||||
|
||||
<target name="-javadoc-all" unless="langtools.tool.name">
|
||||
<echo level="info" message="Generate javadoc for all tools"/>
|
||||
<echo level="verbose" message="(Set langtools.tool.name to generate javadoc for a single tool)"/>
|
||||
<antcall>
|
||||
<target name="langtools.javadoc"/>
|
||||
<target name="-show-javadoc"/>
|
||||
</antcall>
|
||||
</target>
|
||||
<target name="javadoc" depends="langtools.javadoc,-show-javadoc" />
|
||||
|
||||
<target name="-show-javadoc" if="netbeans.home">
|
||||
<!-- what if doing javadoc for all? -->
|
||||
<nbbrowse file="${build.javadoc.dir}/${langtools.tool.name}/index.html"/>
|
||||
<nbbrowse file="${build.javadoc.dir}/index.html"/>
|
||||
</target>
|
||||
|
||||
<!-- Prompt for values. -->
|
||||
@ -253,6 +235,15 @@
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="-setup-bootclasspath">
|
||||
<condition property="use_bootstrap" value="bootstrap-" else="">
|
||||
<isset property="langtools.tool.bootstrap"/>
|
||||
</condition>
|
||||
<condition property="with_bootclasspath" value="${langtools.boot.classes}" else="${langtools.classes}">
|
||||
<isset property="langtools.tool.bootstrap"/>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<!-- Macro to run a tool or selected class - used by run* and debug* tasks -->
|
||||
<target name="-def-run">
|
||||
<macrodef name="run">
|
||||
@ -262,7 +253,7 @@
|
||||
<attribute name="jpda.jvmargs" default=""/>
|
||||
|
||||
<sequential>
|
||||
<java fork="true" jvm="${target.java}" classname="@{mainclass}">
|
||||
<java fork="true" jvm="${target.java.home}/bin/java" classname="@{mainclass}">
|
||||
<jvmarg line="-Xbootclasspath/p:@{bcp}"/>
|
||||
<jvmarg line="@{jpda.jvmargs}"/>
|
||||
<arg line="@{args}"/>
|
||||
@ -278,11 +269,11 @@
|
||||
<sequential>
|
||||
<nbjpdastart name="${ant.project.name}" addressproperty="jpda.address" transport="dt_socket">
|
||||
<bootclasspath>
|
||||
<pathelement location="${build.classes.dir}"/>
|
||||
<pathelement path="${langtools.classes}"/>
|
||||
<pathelement location="${target.java.home}/jre/lib/rt.jar"/>
|
||||
</bootclasspath>
|
||||
<sourcepath>
|
||||
<path refid="src.dirs"/>
|
||||
<pathelement path="${langtools.sources}"/>
|
||||
</sourcepath>
|
||||
</nbjpdastart>
|
||||
<property
|
||||
|
@ -107,7 +107,7 @@
|
||||
</action>
|
||||
<action name="compile.single">
|
||||
<target>compile-single</target>
|
||||
<property name="srcdir">src/java.base/share/classes</property>
|
||||
<property name="module.name">java.base</property>
|
||||
<context>
|
||||
<property>includes</property>
|
||||
<folder>${root}/src/java.base/share/classes</folder>
|
||||
@ -120,7 +120,7 @@
|
||||
</action>
|
||||
<action name="compile.single">
|
||||
<target>compile-single</target>
|
||||
<property name="srcdir">src/java.compiler/share/classes</property>
|
||||
<property name="module.name">java.compiler</property>
|
||||
<context>
|
||||
<property>includes</property>
|
||||
<folder>${root}/src/java.compiler/share/classes</folder>
|
||||
@ -133,7 +133,7 @@
|
||||
</action>
|
||||
<action name="compile.single">
|
||||
<target>compile-single</target>
|
||||
<property name="srcdir">src/jdk.compiler/share/classes</property>
|
||||
<property name="module.name">jdk.compiler</property>
|
||||
<context>
|
||||
<property>includes</property>
|
||||
<folder>${root}/src/jdk.compiler/share/classes</folder>
|
||||
@ -146,7 +146,7 @@
|
||||
</action>
|
||||
<action name="compile.single">
|
||||
<target>compile-single</target>
|
||||
<property name="srcdir">src/jdk.dev/share/classes</property>
|
||||
<property name="module.name">jdk.dev</property>
|
||||
<context>
|
||||
<property>includes</property>
|
||||
<folder>${root}/src/jdk.dev/share/classes</folder>
|
||||
@ -159,7 +159,7 @@
|
||||
</action>
|
||||
<action name="compile.single">
|
||||
<target>compile-single</target>
|
||||
<property name="srcdir">src/jdk.javadoc/share/classes</property>
|
||||
<property name="module.name">jdk.javadoc</property>
|
||||
<context>
|
||||
<property>includes</property>
|
||||
<folder>${root}/src/jdk.javadoc/share/classes</folder>
|
||||
@ -333,7 +333,7 @@
|
||||
</action>
|
||||
<action name="debug.fix">
|
||||
<target>debug-fix</target>
|
||||
<property name="srcdir">src/java.base/share/classes</property>
|
||||
<property name="module.name">java.base</property>
|
||||
<context>
|
||||
<property>class</property>
|
||||
<folder>${root}/src/java.base/share/classes</folder>
|
||||
@ -346,7 +346,7 @@
|
||||
</action>
|
||||
<action name="debug.fix">
|
||||
<target>debug-fix</target>
|
||||
<property name="srcdir">src/java.compiler/share/classes</property>
|
||||
<property name="module.name">java.compiler</property>
|
||||
<context>
|
||||
<property>class</property>
|
||||
<folder>${root}/src/java.compiler/share/classes</folder>
|
||||
@ -359,7 +359,7 @@
|
||||
</action>
|
||||
<action name="debug.fix">
|
||||
<target>debug-fix</target>
|
||||
<property name="srcdir">src/jdk.compiler/share/classes</property>
|
||||
<property name="module.name">jdk.compiler</property>
|
||||
<context>
|
||||
<property>class</property>
|
||||
<folder>${root}/src/jdk.compiler/share/classes</folder>
|
||||
@ -372,7 +372,7 @@
|
||||
</action>
|
||||
<action name="debug.fix">
|
||||
<target>debug-fix</target>
|
||||
<property name="srcdir">src/jdk.dev/share/classes</property>
|
||||
<property name="module.name">jdk.dev</property>
|
||||
<context>
|
||||
<property>class</property>
|
||||
<folder>${root}/src/jdk.dev/share/classes</folder>
|
||||
@ -385,7 +385,7 @@
|
||||
</action>
|
||||
<action name="debug.fix">
|
||||
<target>debug-fix</target>
|
||||
<property name="srcdir">src/jdk.dev/share/classes</property>
|
||||
<property name="module.name">jdk.javadoc</property>
|
||||
<context>
|
||||
<property>class</property>
|
||||
<folder>${root}/src/jdk.javadoc/share/classes</folder>
|
||||
@ -478,11 +478,31 @@
|
||||
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/4">
|
||||
<compilation-unit>
|
||||
<package-root>${root}/src/java.base/share/classes</package-root>
|
||||
<built-to>${root}/build/java.base/classes</built-to>
|
||||
<source-level>1.8</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>${root}/src/java.compiler/share/classes</package-root>
|
||||
<classpath mode="compile">${root}/build/java.base/classes</classpath>
|
||||
<built-to>${root}/build/java.compiler/classes</built-to>
|
||||
<source-level>1.8</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>${root}/src/jdk.compiler/share/classes</package-root>
|
||||
<classpath mode="compile">${root}/build/java.base/classes:${root}/build/java.compiler/classes</classpath>
|
||||
<built-to>${root}/build/jdk.compiler/classes</built-to>
|
||||
<source-level>1.8</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>${root}/src/jdk.dev/share/classes</package-root>
|
||||
<classpath mode="compile">${root}/build/java.base/classes:${root}/build/java.compiler/classes:${root}/build/jdk.compiler/classes</classpath>
|
||||
<built-to>${root}/build/jdk.dev/classes</built-to>
|
||||
<source-level>1.8</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>${root}/src/jdk.javadoc/share/classes</package-root>
|
||||
<built-to>${root}/build/classes</built-to>
|
||||
<classpath mode="compile">${root}/build/java.base/classes:${root}/build/java.compiler/classes:${root}/build/jdk.compiler/classes</classpath>
|
||||
<built-to>${root}/build/jdk.javadoc/classes</built-to>
|
||||
<source-level>1.8</source-level>
|
||||
</compilation-unit>
|
||||
</java-data>
|
||||
|
@ -74,7 +74,18 @@ public class SelectToolTask extends Task {
|
||||
|
||||
enum ToolChoices {
|
||||
NONE(""),
|
||||
JAVAC("javac"),
|
||||
BOOSTRAP_JAVAC("bootstrap-javac", true) {
|
||||
@Override
|
||||
public ToolChoices baseTool() {
|
||||
return JAVAC;
|
||||
}
|
||||
},
|
||||
JAVAC("javac") {
|
||||
@Override
|
||||
public ToolChoices asBootstrap() {
|
||||
return BOOSTRAP_JAVAC;
|
||||
}
|
||||
},
|
||||
JAVADOC("javadoc"),
|
||||
JAVAH("javah"),
|
||||
JAVAP("javap");
|
||||
@ -91,6 +102,14 @@ public class SelectToolTask extends Task {
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
|
||||
public ToolChoices asBootstrap() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolChoices baseTool() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toolName;
|
||||
@ -176,9 +195,11 @@ public class SelectToolTask extends Task {
|
||||
JOptionPane p = createPane(guiProps);
|
||||
p.createDialog("Select Tool").setVisible(true);
|
||||
|
||||
toolName = ((ToolChoices)toolChoice.getSelectedItem()).toolName;
|
||||
ToolChoices tool = (ToolChoices)toolChoice.getSelectedItem();
|
||||
|
||||
toolName = tool.baseTool().toolName;
|
||||
toolBootstrap = tool.bootstrap;
|
||||
toolArgs = argsField.getText();
|
||||
toolBootstrap = bootstrapCheckbox.isSelected();
|
||||
if (defaultCheck.isSelected()) {
|
||||
if (toolName.equals("")) {
|
||||
fileProps.remove("tool.name");
|
||||
@ -213,30 +234,31 @@ public class SelectToolTask extends Task {
|
||||
EnumSet<ToolChoices> toolChoices = toolProperty == null ?
|
||||
EnumSet.allOf(ToolChoices.class) : EnumSet.range(ToolChoices.JAVAC, ToolChoices.JAVAP);
|
||||
toolChoice = new JComboBox<>(toolChoices.toArray());
|
||||
if (toolName != null)
|
||||
toolChoice.setSelectedItem(ToolChoices.valueOf(toolName.toUpperCase()));
|
||||
ToolChoices tool = toolName != null ? ToolChoices.valueOf(toolName.toUpperCase()) : null;
|
||||
if (toolName != null) {
|
||||
if (toolBootstrap)
|
||||
tool = tool.asBootstrap();
|
||||
toolChoice.setSelectedItem(tool);
|
||||
}
|
||||
toolChoice.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
String tn = ((ToolChoices)e.getItem()).toolName;
|
||||
argsField.setText(getDefaultArgsForTool(props, tn));
|
||||
ToolChoices tool = (ToolChoices)e.getItem();
|
||||
argsField.setText(getDefaultArgsForTool(props, tool));
|
||||
if (toolProperty != null)
|
||||
okButton.setEnabled(!tn.equals(""));
|
||||
okButton.setEnabled(tool != ToolChoices.NONE);
|
||||
}
|
||||
});
|
||||
GridBagConstraints checkConstraint = new GridBagConstraints();
|
||||
fc.anchor = GridBagConstraints.EAST;
|
||||
|
||||
GridBagConstraints toolConstraint = new GridBagConstraints();
|
||||
fc.anchor = GridBagConstraints.WEST;
|
||||
|
||||
toolPane.add(toolChoice, toolConstraint);
|
||||
bootstrapCheckbox = new JCheckBox("bootstrap", toolBootstrap);
|
||||
toolPane.add(bootstrapCheckbox, checkConstraint);
|
||||
|
||||
body.add(toolPane, fc);
|
||||
|
||||
argsField = new JTextField(getDefaultArgsForTool(props, toolName), 40);
|
||||
argsField = new JTextField(getDefaultArgsForTool(props, tool), 40);
|
||||
if (toolProperty == null || argsProperty != null) {
|
||||
JLabel argsLabel = new JLabel("Args:");
|
||||
body.add(argsLabel, lc);
|
||||
@ -322,8 +344,11 @@ public class SelectToolTask extends Task {
|
||||
}
|
||||
}
|
||||
|
||||
String getDefaultArgsForTool(Properties props, String tn) {
|
||||
return (tn == null || tn.equals("")) ? "" : props.getProperty(tn + ".args", "");
|
||||
String getDefaultArgsForTool(Properties props, ToolChoices tool) {
|
||||
if (tool == null)
|
||||
return "";
|
||||
String toolName = tool.baseTool().toolName;
|
||||
return toolName.equals("") ? "" : props.getProperty(toolName + ".args", "");
|
||||
}
|
||||
|
||||
// Ant task parameters
|
||||
@ -335,7 +360,6 @@ public class SelectToolTask extends Task {
|
||||
|
||||
// GUI components
|
||||
private JComboBox<?> toolChoice;
|
||||
private JCheckBox bootstrapCheckbox;
|
||||
private JTextField argsField;
|
||||
private JCheckBox defaultCheck;
|
||||
private JButton okButton;
|
||||
|
@ -37,13 +37,19 @@ public interface TaskListener
|
||||
{
|
||||
/**
|
||||
* Invoked when an event has begun.
|
||||
*
|
||||
* @implSpec The default implementation of this method does nothing.
|
||||
*
|
||||
* @param e the event
|
||||
*/
|
||||
public void started(TaskEvent e);
|
||||
default void started(TaskEvent e) { }
|
||||
|
||||
/**
|
||||
* Invoked when an event has been completed.
|
||||
*
|
||||
* @implSpec The default implementation of this method does nothing.
|
||||
*
|
||||
* @param e the event
|
||||
*/
|
||||
public void finished(TaskEvent e);
|
||||
default void finished(TaskEvent e) { }
|
||||
}
|
||||
|
@ -305,7 +305,32 @@ public abstract class Scope {
|
||||
* the table of its outer scope.
|
||||
*/
|
||||
public WriteableScope dupUnshared(Symbol newOwner) {
|
||||
return new ScopeImpl(this, newOwner, this.table.clone(), this.nelems);
|
||||
if (shared > 0) {
|
||||
//The nested Scopes might have already added something to the table, so all items
|
||||
//that don't originate in this Scope or any of its outer Scopes need to be cleared:
|
||||
Set<Scope> acceptScopes = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
ScopeImpl c = this;
|
||||
while (c != null) {
|
||||
acceptScopes.add(c);
|
||||
c = c.next;
|
||||
}
|
||||
int n = 0;
|
||||
Entry[] oldTable = this.table;
|
||||
Entry[] newTable = new Entry[this.table.length];
|
||||
for (int i = 0; i < oldTable.length; i++) {
|
||||
Entry e = oldTable[i];
|
||||
while (e != null && e != sentinel && !acceptScopes.contains(e.scope)) {
|
||||
e = e.shadowed;
|
||||
}
|
||||
if (e != null) {
|
||||
n++;
|
||||
newTable[i] = e;
|
||||
}
|
||||
}
|
||||
return new ScopeImpl(this, newOwner, newTable, n);
|
||||
} else {
|
||||
return new ScopeImpl(this, newOwner, this.table.clone(), this.nelems);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove all entries of this scope from its table, if shared
|
||||
|
@ -145,7 +145,7 @@ public class TypeAnnotationPosition {
|
||||
public final int bound_index;
|
||||
|
||||
// For type parameter and method parameter
|
||||
public final int parameter_index;
|
||||
public int parameter_index;
|
||||
|
||||
// For class extends, implements, and throws clauses
|
||||
public final int type_index;
|
||||
|
@ -1196,35 +1196,35 @@ public class Attr extends JCTree.Visitor {
|
||||
boolean hasDefault = false; // Is there a default label?
|
||||
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
|
||||
JCCase c = l.head;
|
||||
if (c.pat != null) {
|
||||
if (enumSwitch) {
|
||||
Symbol sym = enumConstant(c.pat, seltype);
|
||||
if (sym == null) {
|
||||
log.error(c.pat.pos(), "enum.label.must.be.unqualified.enum");
|
||||
} else if (!labels.add(sym)) {
|
||||
log.error(c.pos(), "duplicate.case.label");
|
||||
}
|
||||
} else {
|
||||
Type pattype = attribExpr(c.pat, switchEnv, seltype);
|
||||
if (!pattype.hasTag(ERROR)) {
|
||||
if (pattype.constValue() == null) {
|
||||
log.error(c.pat.pos(),
|
||||
(stringSwitch ? "string.const.req" : "const.expr.req"));
|
||||
} else if (labels.contains(pattype.constValue())) {
|
||||
log.error(c.pos(), "duplicate.case.label");
|
||||
} else {
|
||||
labels.add(pattype.constValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (hasDefault) {
|
||||
log.error(c.pos(), "duplicate.default.label");
|
||||
} else {
|
||||
hasDefault = true;
|
||||
}
|
||||
Env<AttrContext> caseEnv =
|
||||
switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
|
||||
try {
|
||||
if (c.pat != null) {
|
||||
if (enumSwitch) {
|
||||
Symbol sym = enumConstant(c.pat, seltype);
|
||||
if (sym == null) {
|
||||
log.error(c.pat.pos(), "enum.label.must.be.unqualified.enum");
|
||||
} else if (!labels.add(sym)) {
|
||||
log.error(c.pos(), "duplicate.case.label");
|
||||
}
|
||||
} else {
|
||||
Type pattype = attribExpr(c.pat, switchEnv, seltype);
|
||||
if (!pattype.hasTag(ERROR)) {
|
||||
if (pattype.constValue() == null) {
|
||||
log.error(c.pat.pos(),
|
||||
(stringSwitch ? "string.const.req" : "const.expr.req"));
|
||||
} else if (labels.contains(pattype.constValue())) {
|
||||
log.error(c.pos(), "duplicate.case.label");
|
||||
} else {
|
||||
labels.add(pattype.constValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (hasDefault) {
|
||||
log.error(c.pos(), "duplicate.default.label");
|
||||
} else {
|
||||
hasDefault = true;
|
||||
}
|
||||
attribStats(c.stats, caseEnv);
|
||||
} finally {
|
||||
caseEnv.info.scope.leave();
|
||||
@ -1429,21 +1429,28 @@ public class Attr extends JCTree.Visitor {
|
||||
case APPLY:
|
||||
JCMethodInvocation speculativeMethodTree =
|
||||
(JCMethodInvocation)deferredAttr.attribSpeculative(tree, env, unknownExprInfo);
|
||||
Type owntype = TreeInfo.symbol(speculativeMethodTree.meth).type.getReturnType();
|
||||
return types.unboxedTypeOrType(owntype).isPrimitive();
|
||||
Symbol msym = TreeInfo.symbol(speculativeMethodTree.meth);
|
||||
Type receiverType = speculativeMethodTree.meth.hasTag(IDENT) ?
|
||||
env.enclClass.type :
|
||||
((JCFieldAccess)speculativeMethodTree.meth).selected.type;
|
||||
Type owntype = types.memberType(receiverType, msym).getReturnType();
|
||||
return primitiveOrBoxed(owntype);
|
||||
case NEWCLASS:
|
||||
JCExpression className =
|
||||
removeClassParams.translate(((JCNewClass)tree).clazz);
|
||||
JCExpression speculativeNewClassTree =
|
||||
(JCExpression)deferredAttr.attribSpeculative(className, env, unknownTypeInfo);
|
||||
return types.unboxedTypeOrType(speculativeNewClassTree.type).isPrimitive();
|
||||
return primitiveOrBoxed(speculativeNewClassTree.type);
|
||||
default:
|
||||
Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo).type;
|
||||
speculativeType = types.unboxedTypeOrType(speculativeType);
|
||||
return speculativeType.isPrimitive();
|
||||
return primitiveOrBoxed(speculativeType);
|
||||
}
|
||||
}
|
||||
//where
|
||||
boolean primitiveOrBoxed(Type t) {
|
||||
return (!t.hasTag(TYPEVAR) && types.unboxedTypeOrType(t).isPrimitive());
|
||||
}
|
||||
|
||||
TreeTranslator removeClassParams = new TreeTranslator() {
|
||||
@Override
|
||||
public void visitTypeApply(JCTypeApply tree) {
|
||||
|
@ -1213,7 +1213,10 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||
return;
|
||||
}
|
||||
scan(tree.falsepart);
|
||||
result = reduce(ArgumentExpressionKind.PRIMITIVE);
|
||||
result = reduce(ArgumentExpressionKind.PRIMITIVE).isPrimitive() ?
|
||||
ArgumentExpressionKind.PRIMITIVE :
|
||||
ArgumentExpressionKind.POLY;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2642,9 +2642,10 @@ public class Lower extends TreeTranslator {
|
||||
syms.intType, tree.sym);
|
||||
ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
|
||||
|
||||
tree.params = tree.params.prepend(ordParam).prepend(nameParam);
|
||||
|
||||
MethodSymbol m = tree.sym;
|
||||
tree.params = tree.params.prepend(ordParam).prepend(nameParam);
|
||||
incrementParamTypeAnnoIndexes(m, 2);
|
||||
|
||||
m.extraParams = m.extraParams.prepend(ordParam.sym);
|
||||
m.extraParams = m.extraParams.prepend(nameParam.sym);
|
||||
Type olderasure = m.erasure(types);
|
||||
@ -2667,6 +2668,17 @@ public class Lower extends TreeTranslator {
|
||||
}
|
||||
}
|
||||
//where
|
||||
private void incrementParamTypeAnnoIndexes(MethodSymbol m,
|
||||
int amount) {
|
||||
for (final Attribute.TypeCompound anno : m.getRawTypeAttributes()) {
|
||||
// Increment the parameter_index of any existing formal
|
||||
// parameter annotations.
|
||||
if (anno.position.type == TargetType.METHOD_FORMAL_PARAMETER) {
|
||||
anno.position.parameter_index += amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitMethodDefInternal(JCMethodDecl tree) {
|
||||
if (tree.name == names.init &&
|
||||
(currentClass.isInner() || currentClass.isLocal())) {
|
||||
@ -2697,8 +2709,10 @@ public class Lower extends TreeTranslator {
|
||||
// Add this$n (if needed) in front of and free variables behind
|
||||
// constructor parameter list.
|
||||
tree.params = tree.params.appendList(fvdefs);
|
||||
if (currentClass.hasOuterInstance())
|
||||
if (currentClass.hasOuterInstance()) {
|
||||
tree.params = tree.params.prepend(otdef);
|
||||
incrementParamTypeAnnoIndexes(m, 1);
|
||||
}
|
||||
|
||||
// If this is an initial constructor, i.e., it does not start with
|
||||
// this(...), insert initializers for this$n and proxies
|
||||
|
@ -111,6 +111,8 @@ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter {
|
||||
Collection<String> args = formatArguments(d, l);
|
||||
String msg = localize(l, d.getCode(), args.toArray());
|
||||
String[] lines = msg.split("\n");
|
||||
if (lines.length == 0) // will happen when msg only contains one or more separators: "\n", "\n\n", etc.
|
||||
lines = new String[] { "" };
|
||||
if (getConfiguration().getVisible().contains(DiagnosticPart.SUMMARY)) {
|
||||
currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUMMARY);
|
||||
buf.append(indent(lines[0], currentIndentation)); //summary
|
||||
|
@ -218,21 +218,21 @@ public class ClientMain {
|
||||
// Collect the name of all compiled packages.
|
||||
Set<String> recently_compiled = new HashSet<>();
|
||||
boolean[] rc = new boolean[1];
|
||||
Sjavac sjavac;
|
||||
boolean background = Util.extractBooleanOption("background", options.getServerConf(), true);
|
||||
Sjavac sjavac;
|
||||
// Create an sjavac implementation to be used for compilation
|
||||
if (background) {
|
||||
sjavac = new SjavacClient(options);
|
||||
} else {
|
||||
int poolsize = Util.extractIntOption("poolsize", options.getServerConf());
|
||||
if (poolsize <= 0)
|
||||
poolsize = Runtime.getRuntime().availableProcessors();
|
||||
sjavac = new PooledSjavac(new SjavacImpl(), poolsize);
|
||||
}
|
||||
|
||||
do {
|
||||
// Clean out artifacts in tainted packages.
|
||||
javac_state.deleteClassArtifactsInTaintedPackages();
|
||||
// Create an sjavac implementation to be used for compilation
|
||||
if (background) {
|
||||
sjavac = new SjavacClient(options);
|
||||
} else {
|
||||
int poolsize = Util.extractIntOption("poolsize", options.getServerConf());
|
||||
if (poolsize <= 0)
|
||||
poolsize = Runtime.getRuntime().availableProcessors();
|
||||
sjavac = new PooledSjavac(new SjavacImpl(), poolsize);
|
||||
}
|
||||
|
||||
again = javac_state.performJavaCompilations(sjavac, options, recently_compiled, rc);
|
||||
if (!rc[0]) break;
|
||||
} while (again);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2014, 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
|
||||
@ -26,7 +26,8 @@
|
||||
* @bug 6508981
|
||||
* @summary cleanup file separator handling in JavacFileManager
|
||||
* (This test is specifically to test the new impl of inferBinaryName)
|
||||
* @build p.A
|
||||
* @library /tools/lib
|
||||
* @build ToolBox p.A
|
||||
* @run main TestInferBinaryName
|
||||
*/
|
||||
|
||||
@ -61,51 +62,75 @@ public class TestInferBinaryName {
|
||||
//System.err.println(System.getProperties());
|
||||
testDirectory();
|
||||
testSymbolArchive();
|
||||
testZipArchive();
|
||||
testZipFileIndexArchive();
|
||||
testZipFileIndexArchive2();
|
||||
|
||||
File testJar = createJar();
|
||||
|
||||
testZipArchive(testJar);
|
||||
testZipFileIndexArchive(testJar);
|
||||
testZipFileIndexArchive2(testJar);
|
||||
if (errors > 0)
|
||||
throw new Exception(errors + " error found");
|
||||
}
|
||||
|
||||
File createJar() throws IOException {
|
||||
File f = new File("test.jar");
|
||||
try (JavaFileManager fm = new JavacFileManager(new Context(), false, null)) {
|
||||
ToolBox tb = new ToolBox();
|
||||
tb.new JarTask(f.getPath())
|
||||
.files(fm, StandardLocation.PLATFORM_CLASS_PATH, "java.lang.*")
|
||||
.run();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void testDirectory() throws IOException {
|
||||
String testClassName = "p.A";
|
||||
JavaFileManager fm =
|
||||
getFileManager("test.classes", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
|
||||
test("testDirectory",
|
||||
fm, testClassName, "com.sun.tools.javac.file.RegularFileObject");
|
||||
List<File> testClasses = Arrays.asList(new File(System.getProperty("test.classes")));
|
||||
try (JavaFileManager fm =
|
||||
getFileManager(testClasses, USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX)) {
|
||||
test("testDirectory",
|
||||
fm, testClassName, "com.sun.tools.javac.file.RegularFileObject");
|
||||
}
|
||||
}
|
||||
|
||||
void testSymbolArchive() throws IOException {
|
||||
String testClassName = "java.lang.String";
|
||||
JavaFileManager fm =
|
||||
getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX);
|
||||
test("testSymbolArchive",
|
||||
fm, testClassName, "com.sun.tools.javac.file.SymbolArchive$SymbolFileObject");
|
||||
List<File> path = getPath(System.getProperty("sun.boot.class.path"));
|
||||
try (JavaFileManager fm =
|
||||
getFileManager(path, USE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX)) {
|
||||
test("testSymbolArchive",
|
||||
fm, testClassName, "com.sun.tools.javac.file.SymbolArchive$SymbolFileObject");
|
||||
}
|
||||
}
|
||||
|
||||
void testZipArchive() throws IOException {
|
||||
void testZipArchive(File testJar) throws IOException {
|
||||
String testClassName = "java.lang.String";
|
||||
JavaFileManager fm =
|
||||
getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX);
|
||||
test("testZipArchive",
|
||||
fm, testClassName, "com.sun.tools.javac.file.ZipArchive$ZipFileObject");
|
||||
List<File> path = Arrays.asList(testJar);
|
||||
try (JavaFileManager fm =
|
||||
getFileManager(path, IGNORE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX)) {
|
||||
test("testZipArchive",
|
||||
fm, testClassName, "com.sun.tools.javac.file.ZipArchive$ZipFileObject");
|
||||
}
|
||||
}
|
||||
|
||||
void testZipFileIndexArchive() throws IOException {
|
||||
void testZipFileIndexArchive(File testJar) throws IOException {
|
||||
String testClassName = "java.lang.String";
|
||||
JavaFileManager fm =
|
||||
getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
|
||||
test("testZipFileIndexArchive",
|
||||
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
||||
List<File> path = Arrays.asList(testJar);
|
||||
try (JavaFileManager fm =
|
||||
getFileManager(path, USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX)) {
|
||||
test("testZipFileIndexArchive",
|
||||
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
||||
}
|
||||
}
|
||||
|
||||
void testZipFileIndexArchive2() throws IOException {
|
||||
void testZipFileIndexArchive2(File testJar) throws IOException {
|
||||
String testClassName = "java.lang.String";
|
||||
JavaFileManager fm =
|
||||
getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
|
||||
test("testZipFileIndexArchive2",
|
||||
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
||||
List<File> path = Arrays.asList(testJar);
|
||||
try (JavaFileManager fm =
|
||||
getFileManager(path, IGNORE_SYMBOL_FILE, USE_ZIP_FILE_INDEX)) {
|
||||
test("testZipFileIndexArchive2",
|
||||
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,7 +158,7 @@ public class TestInferBinaryName {
|
||||
System.err.println("OK");
|
||||
}
|
||||
|
||||
JavaFileManager getFileManager(String classpathProperty,
|
||||
JavaFileManager getFileManager(List<File> path,
|
||||
boolean symFileKind,
|
||||
boolean zipFileIndexKind)
|
||||
throws IOException {
|
||||
@ -145,7 +170,6 @@ public class TestInferBinaryName {
|
||||
if (symFileKind == IGNORE_SYMBOL_FILE)
|
||||
options.put("ignore.symbol.file", "true");
|
||||
JavacFileManager fm = new JavacFileManager(ctx, false, null);
|
||||
List<File> path = getPath(System.getProperty(classpathProperty));
|
||||
fm.setLocation(CLASS_PATH, path);
|
||||
return fm;
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 4974927
|
||||
* @bug 4974927 8064464
|
||||
* @summary The compiler was allowing void types in its parsing of conditional expressions.
|
||||
* @author tball
|
||||
*
|
||||
* @compile/fail/ref=ConditionalWithVoid.out -XDrawDiagnostics ConditionalWithVoid.java
|
||||
*/
|
||||
public class ConditionalWithVoid {
|
||||
public int test(Object o) {
|
||||
// Should fail to compile since Object.wait() has a void return type.
|
||||
public void test(Object o) {
|
||||
// Should fail to compile since Object.wait() has a void return type. Poly case.
|
||||
System.out.println(o instanceof String ? o.hashCode() : o.wait());
|
||||
// Should fail to compile since Object.wait() has a void return type. Standalone case.
|
||||
(o instanceof String ? o.hashCode() : o.wait()).toString();
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,3 @@
|
||||
ConditionalWithVoid.java:12:48: compiler.err.neither.conditional.subtype: java.lang.Integer, void
|
||||
1 error
|
||||
ConditionalWithVoid.java:12:71: compiler.err.void.not.allowed.here
|
||||
ConditionalWithVoid.java:14:30: compiler.err.neither.conditional.subtype: java.lang.Integer, void
|
||||
2 errors
|
||||
|
@ -0,0 +1,950 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
|
||||
/**
|
||||
* A class providing utilities for writing tests that inspect class
|
||||
* files directly, looking for specific type annotations.
|
||||
*
|
||||
* Note: this framework does not currently handle repeating
|
||||
* annotations.
|
||||
*/
|
||||
public class ClassfileInspector {
|
||||
|
||||
/**
|
||||
* A group of expected annotations to be found in a given class.
|
||||
* If the class name is null, then the template will be applied to
|
||||
* every class.
|
||||
*/
|
||||
public static class Expected {
|
||||
/**
|
||||
* The name of the class. If {@code null} this template will
|
||||
* apply to every class; otherwise, it will only be applied to
|
||||
* the named class.
|
||||
*/
|
||||
public final String classname;
|
||||
|
||||
/**
|
||||
* The expected class annotations. These will be checked
|
||||
* against the class' attributes.
|
||||
*/
|
||||
public final ExpectedTypeAnnotation[] classAnnos;
|
||||
|
||||
/**
|
||||
* The expected method annotations. These will be checked
|
||||
* against all methods in the class.
|
||||
*/
|
||||
public final ExpectedMethodTypeAnnotation[] methodAnnos;
|
||||
|
||||
/**
|
||||
* The expected field annotations. These will be checked
|
||||
* against all fields in the class.
|
||||
*/
|
||||
public final ExpectedFieldTypeAnnotation[] fieldAnnos;
|
||||
|
||||
/**
|
||||
* Create an {@code Expected} from its components.
|
||||
*
|
||||
* @param classname The name of the class to match, or {@code
|
||||
* null} for all classes.
|
||||
* @param classAnnos The expected class annotations.
|
||||
* @param methodAnnos The expected method annotations.
|
||||
* @param fieldAnnos The expected field annotations.
|
||||
*/
|
||||
public Expected(String classname,
|
||||
ExpectedTypeAnnotation[] classAnnos,
|
||||
ExpectedMethodTypeAnnotation[] methodAnnos,
|
||||
ExpectedFieldTypeAnnotation[] fieldAnnos) {
|
||||
this.classname = classname;
|
||||
this.classAnnos = classAnnos;
|
||||
this.methodAnnos = methodAnnos;
|
||||
this.fieldAnnos = fieldAnnos;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final String newline = System.lineSeparator();
|
||||
sb.append("Expected on class ").append(classname);
|
||||
if (null != classAnnos) {
|
||||
sb.append(newline).append("Class annotations:").append(newline);
|
||||
for(ExpectedTypeAnnotation anno : classAnnos) {
|
||||
sb.append(anno).append(newline);
|
||||
}
|
||||
}
|
||||
if (null != methodAnnos) {
|
||||
sb.append(newline).append("Method annotations:").append(newline);
|
||||
for(ExpectedTypeAnnotation anno : methodAnnos) {
|
||||
sb.append(anno).append(newline);
|
||||
}
|
||||
}
|
||||
if (null != fieldAnnos) {
|
||||
sb.append(newline).append("Field annotations:").append(newline);
|
||||
for(ExpectedTypeAnnotation anno : fieldAnnos) {
|
||||
sb.append(anno).append(newline);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* See if this template applies to a class.
|
||||
*
|
||||
* @param classname The classname to check.
|
||||
* @return Whether or not this template should apply.
|
||||
*/
|
||||
public boolean matchClassName(String classname) {
|
||||
return this.classname == null || this.classname.equals(classname);
|
||||
}
|
||||
|
||||
/**
|
||||
* After applying the template to all classes, check to see if
|
||||
* any of the expected annotations weren't matched.
|
||||
*
|
||||
* @return The number of missed matches.
|
||||
*/
|
||||
public int check() {
|
||||
int count = 0;
|
||||
if (classAnnos != null) {
|
||||
for(ExpectedTypeAnnotation expected : classAnnos) {
|
||||
if (!expected.check()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (methodAnnos != null) {
|
||||
for(ExpectedMethodTypeAnnotation expected : methodAnnos) {
|
||||
if (!expected.check()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fieldAnnos != null) {
|
||||
for(ExpectedFieldTypeAnnotation expected : fieldAnnos) {
|
||||
if (!expected.check()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expected type annotation. This is both a superclass for
|
||||
* method and field type annotations, as well as a class for type
|
||||
* annotations on a class.
|
||||
*/
|
||||
public static class ExpectedTypeAnnotation {
|
||||
private int count = 0;
|
||||
protected final String expectedName;
|
||||
protected final int expectedCount;
|
||||
protected final TypeAnnotation.TargetType targetType;
|
||||
protected final int bound_index;
|
||||
protected final int parameter_index;
|
||||
protected final int type_index;
|
||||
protected final int exception_index;
|
||||
protected final TypeAnnotation.Position.TypePathEntry[] typePath;
|
||||
protected final boolean visibility;
|
||||
|
||||
/**
|
||||
* Create an {@code ExpectedTypeAnnotation} from its
|
||||
* components. It is usually a better idea to use a {@code
|
||||
* Builder} to do this.
|
||||
*
|
||||
* @param expectedName The expected annotation name.
|
||||
* @param visibility Whether this annotation should be runtime-visible.
|
||||
* @param expectedCount The number of annotations that should
|
||||
* be seen. If 0, this asserts that the
|
||||
* described annotation is not present.
|
||||
* @param targetType The expected target type.
|
||||
* @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
|
||||
* @param parameter_index The expected parameter index, or
|
||||
* {@code Integer.MIN_VALUE}.
|
||||
* @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
|
||||
* @param exception_index The expected exception index, or
|
||||
* {@code Integer.MIN_VALUE}.
|
||||
* @param typePath The expected type path.
|
||||
*/
|
||||
public ExpectedTypeAnnotation(String expectedName,
|
||||
boolean visibility,
|
||||
int expectedCount,
|
||||
TypeAnnotation.TargetType targetType,
|
||||
int bound_index,
|
||||
int parameter_index,
|
||||
int type_index,
|
||||
int exception_index,
|
||||
TypeAnnotation.Position.TypePathEntry... typePath) {
|
||||
this.expectedName = expectedName;
|
||||
this.visibility = visibility;
|
||||
this.expectedCount = expectedCount;
|
||||
this.targetType = targetType;
|
||||
this.bound_index = bound_index;
|
||||
this.parameter_index = parameter_index;
|
||||
this.type_index = type_index;
|
||||
this.exception_index = exception_index;
|
||||
this.typePath = typePath;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Expected ");
|
||||
sb.append(expectedCount);
|
||||
sb.append(" annotation ");
|
||||
sb.append(expectedName);
|
||||
sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
|
||||
sb.append(targetType);
|
||||
sb.append(", bound_index = ");
|
||||
sb.append(bound_index);
|
||||
sb.append(", parameter_index = ");
|
||||
sb.append(parameter_index);
|
||||
sb.append(", type_index = ");
|
||||
sb.append(type_index);
|
||||
sb.append(", exception_index = ");
|
||||
sb.append(exception_index);
|
||||
sb.append(", type_path = [");
|
||||
for(int i = 0; i < typePath.length; i++) {
|
||||
if (i != 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(typePath[i]);
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* See if this template matches the given visibility.
|
||||
*
|
||||
* @param Whether or not the annotation is visible at runtime.
|
||||
* @return Whether or not this template matches the visibility.
|
||||
*/
|
||||
public boolean matchVisibility(boolean visibility) {
|
||||
return this.visibility == visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempty to match this template against an annotation. If
|
||||
* it does match, then the match count for the template will
|
||||
* be incremented. Otherwise, nothing will be done.
|
||||
*
|
||||
* @param anno The annotation to attempt to match.
|
||||
*/
|
||||
public void matchAnnotation(TypeAnnotation anno) {
|
||||
boolean matches = true;
|
||||
|
||||
try {
|
||||
matches = anno.constant_pool.getUTF8Info(anno.annotation.type_index).value.equals("L" + expectedName + ";");
|
||||
} catch(Exception e) {
|
||||
matches = false;
|
||||
}
|
||||
|
||||
matches = matches && anno.position.type == targetType;
|
||||
matches = matches && anno.position.bound_index == bound_index;
|
||||
matches = matches && anno.position.parameter_index == parameter_index;
|
||||
matches = matches && anno.position.type_index == type_index;
|
||||
matches = matches && anno.position.exception_index == exception_index;
|
||||
matches = matches && anno.position.location.size() == typePath.length;
|
||||
|
||||
if (matches) {
|
||||
int i = 0;
|
||||
for(TypeAnnotation.Position.TypePathEntry entry :
|
||||
anno.position.location) {
|
||||
matches = matches && typePath[i++].equals(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After all matching, check to see if the expected number of
|
||||
* matches equals the actual number. If not, then print a
|
||||
* failure message and return {@code false}.
|
||||
*
|
||||
* @return Whether or not the expected number of matched
|
||||
* equals the actual number.
|
||||
*/
|
||||
public boolean check() {
|
||||
if (count != expectedCount) {
|
||||
System.err.println(this + ", but saw " + count);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder class for creating {@code
|
||||
* ExpectedTypeAnnotation}s in a more convenient fashion. The
|
||||
* constructor for {@code ExpectedTypeAnnotation} takes a
|
||||
* large number of parameters (by necessity). This class
|
||||
* allows users to construct a {@code ExpectedTypeAnnotation}s
|
||||
* using only the ones they need.
|
||||
*/
|
||||
public static class Builder {
|
||||
protected final String expectedName;
|
||||
protected final int expectedCount;
|
||||
protected final TypeAnnotation.TargetType targetType;
|
||||
protected final boolean visibility;
|
||||
protected int bound_index = Integer.MIN_VALUE;
|
||||
protected int parameter_index = Integer.MIN_VALUE;
|
||||
protected int type_index = Integer.MIN_VALUE;
|
||||
protected int exception_index = Integer.MIN_VALUE;
|
||||
protected TypeAnnotation.Position.TypePathEntry[] typePath =
|
||||
new TypeAnnotation.Position.TypePathEntry[0];
|
||||
|
||||
/**
|
||||
* Create a {@code Builder} from the mandatory parameters.
|
||||
*
|
||||
* @param expectedName The expected annotation name.
|
||||
* @param targetType The expected target type.
|
||||
* @param visibility Whether this annotation should be runtime-visible.
|
||||
* @param expectedCount The number of annotations that should be seen.
|
||||
*/
|
||||
public Builder(String expectedName,
|
||||
TypeAnnotation.TargetType targetType,
|
||||
boolean visibility,
|
||||
int expectedCount) {
|
||||
this.expectedName = expectedName;
|
||||
this.visibility = visibility;
|
||||
this.expectedCount = expectedCount;
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code ExpectedTypeAnnotation} from all
|
||||
* parameters that have been provided. The default values
|
||||
* will be used for those that have not.
|
||||
*
|
||||
* @return The cretaed {@code ExpectedTypeAnnotation}.
|
||||
*/
|
||||
public ExpectedTypeAnnotation build() {
|
||||
return new ExpectedTypeAnnotation(expectedName, visibility,
|
||||
expectedCount, targetType,
|
||||
bound_index, parameter_index,
|
||||
type_index, exception_index,
|
||||
typePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a bound index parameter.
|
||||
*
|
||||
* @param bound_index The bound_index value.
|
||||
*/
|
||||
public Builder setBoundIndex(int bound_index) {
|
||||
this.bound_index = bound_index;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a parameter index parameter.
|
||||
*
|
||||
* @param bound_index The parameter_index value.
|
||||
*/
|
||||
public Builder setParameterIndex(int parameter_index) {
|
||||
this.parameter_index = parameter_index;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a type index parameter.
|
||||
*
|
||||
* @param type_index The type_index value.
|
||||
*/
|
||||
public Builder setTypeIndex(int type_index) {
|
||||
this.type_index = type_index;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an exception index parameter.
|
||||
*
|
||||
* @param exception_index The exception_index value.
|
||||
*/
|
||||
public Builder setExceptionIndex(int exception_index) {
|
||||
this.exception_index = exception_index;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a type path parameter.
|
||||
*
|
||||
* @param typePath The type path value.
|
||||
*/
|
||||
public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) {
|
||||
this.typePath = typePath;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type annotation found on a method.
|
||||
*/
|
||||
public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation {
|
||||
private final String methodname;
|
||||
|
||||
/**
|
||||
* Create an {@code ExpectedMethodTypeAnnotation} from its
|
||||
* components. It is usually a better idea to use a {@code
|
||||
* Builder} to do this.
|
||||
*
|
||||
* @param methodname The expected method name.
|
||||
* @param expectedName The expected annotation name.
|
||||
* @param visibility Whether this annotation should be runtime-visible.
|
||||
* @param expectedCount The number of annotations that should be seen.
|
||||
* @param targetType The expected target type.
|
||||
* @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
|
||||
* @param parameter_index The expected parameter index, or
|
||||
* {@code Integer.MIN_VALUE}.
|
||||
* @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
|
||||
* @param exception_index The expected exception index, or
|
||||
* {@code Integer.MIN_VALUE}.
|
||||
* @param typePath The expected type path.
|
||||
*/
|
||||
public ExpectedMethodTypeAnnotation(String methodname,
|
||||
String expectedName,
|
||||
boolean visibility,
|
||||
int expectedCount,
|
||||
TypeAnnotation.TargetType targetType,
|
||||
int bound_index,
|
||||
int parameter_index,
|
||||
int type_index,
|
||||
int exception_index,
|
||||
TypeAnnotation.Position.TypePathEntry... typePath) {
|
||||
super(expectedName, visibility, expectedCount, targetType, bound_index,
|
||||
parameter_index, type_index, exception_index, typePath);
|
||||
this.methodname = methodname;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Expected ");
|
||||
sb.append(expectedCount);
|
||||
sb.append(" annotation ");
|
||||
sb.append(expectedName);
|
||||
sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
|
||||
sb.append(targetType);
|
||||
sb.append(", bound_index = ");
|
||||
sb.append(bound_index);
|
||||
sb.append(", parameter_index = ");
|
||||
sb.append(parameter_index);
|
||||
sb.append(", type_index = ");
|
||||
sb.append(type_index);
|
||||
sb.append(", exception_index = ");
|
||||
sb.append(exception_index);
|
||||
sb.append(", type_path = [");
|
||||
for(int i = 0; i < typePath.length; i++) {
|
||||
if (i != 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(typePath[i]);
|
||||
}
|
||||
sb.append("]");
|
||||
sb.append(" on method ");
|
||||
sb.append(methodname);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* See if this template applies to a method.
|
||||
*
|
||||
* @param methodname The method name to check.
|
||||
* @return Whether or not this template should apply.
|
||||
*/
|
||||
public boolean matchMethodName(String methodname) {
|
||||
return this.methodname.equals(methodname);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder class for creating {@code
|
||||
* ExpectedMethodTypeAnnotation}s in a more convenient fashion. The
|
||||
* constructor for {@code ExpectedMethodTypeAnnotation} takes a
|
||||
* large number of parameters (by necessity). This class
|
||||
* allows users to construct a {@code ExpectedMethodTypeAnnotation}s
|
||||
* using only the ones they need.
|
||||
*/
|
||||
public static class Builder extends ExpectedTypeAnnotation.Builder {
|
||||
protected final String methodname;
|
||||
|
||||
/**
|
||||
* Create a {@code Builder} from the mandatory parameters.
|
||||
*
|
||||
* @param methodname The expected method name.
|
||||
* @param expectedName The expected annotation name.
|
||||
* @param targetType The expected target type.
|
||||
* @param visibility Whether this annotation should be runtime-visible.
|
||||
* @param expectedCount The number of annotations that should be seen.
|
||||
*/
|
||||
public Builder(String methodname,
|
||||
String expectedName,
|
||||
TypeAnnotation.TargetType targetType,
|
||||
boolean visibility,
|
||||
int expectedCount) {
|
||||
super(expectedName, targetType, visibility, expectedCount);
|
||||
this.methodname = methodname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code ExpectedMethodTypeAnnotation} from all
|
||||
* parameters that have been provided. The default values
|
||||
* will be used for those that have not.
|
||||
*
|
||||
* @return The cretaed {@code ExpectedMethodTypeAnnotation}.
|
||||
*/
|
||||
public ExpectedMethodTypeAnnotation build() {
|
||||
return new ExpectedMethodTypeAnnotation(methodname, expectedName,
|
||||
visibility, expectedCount,
|
||||
targetType, bound_index,
|
||||
parameter_index, type_index,
|
||||
exception_index, typePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type annotation found on a field.
|
||||
*/
|
||||
public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation {
|
||||
private final String fieldname;
|
||||
|
||||
/**
|
||||
* Create an {@code ExpectedFieldTypeAnnotation} from its
|
||||
* components. It is usually a better idea to use a {@code
|
||||
* Builder} to do this.
|
||||
*
|
||||
* @param fieldname The expected field name.
|
||||
* @param expectedName The expected annotation name.
|
||||
* @param visibility Whether this annotation should be runtime-visible.
|
||||
* @param expectedCount The number of annotations that should be seen.
|
||||
* @param targetType The expected target type.
|
||||
* @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
|
||||
* @param parameter_index The expected parameter index, or
|
||||
* {@code Integer.MIN_VALUE}.
|
||||
* @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
|
||||
* @param exception_index The expected exception index, or
|
||||
* {@code Integer.MIN_VALUE}.
|
||||
* @param typePath The expected type path.
|
||||
*/
|
||||
public ExpectedFieldTypeAnnotation(String fieldname,
|
||||
String expectedName,
|
||||
boolean visibility,
|
||||
int expectedCount,
|
||||
TypeAnnotation.TargetType targetType,
|
||||
int bound_index,
|
||||
int parameter_index,
|
||||
int type_index,
|
||||
int exception_index,
|
||||
TypeAnnotation.Position.TypePathEntry... typePath) {
|
||||
super(expectedName, visibility, expectedCount, targetType, bound_index,
|
||||
parameter_index, type_index, exception_index, typePath);
|
||||
this.fieldname = fieldname;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Expected ").append(expectedCount)
|
||||
.append(" annotation ").append(expectedName)
|
||||
.append(visibility ? ", runtime visibile " : ", runtime invisibile ")
|
||||
.append(targetType)
|
||||
.append(", bound_index = ").append(bound_index)
|
||||
.append(", parameter_index = ").append(parameter_index)
|
||||
.append(", type_index = ").append(type_index)
|
||||
.append(", exception_index = ").append(exception_index)
|
||||
.append(", type_path = [");
|
||||
|
||||
for(int i = 0; i < typePath.length; i++) {
|
||||
if (i != 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(typePath[i]);
|
||||
}
|
||||
sb.append("]")
|
||||
.append(" on field ").append(fieldname);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* See if this template applies to a field.
|
||||
*
|
||||
* @param fieldname The field name to check.
|
||||
* @return Whether or not this template should apply.
|
||||
*/
|
||||
public boolean matchFieldName(String fieldname) {
|
||||
return this.fieldname.equals(fieldname);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder class for creating {@code
|
||||
* ExpectedFieldTypeAnnotation}s in a more convenient fashion. The
|
||||
* constructor for {@code ExpectedFieldTypeAnnotation} takes a
|
||||
* large number of parameters (by necessity). This class
|
||||
* allows users to construct a {@code ExpectedFieldTypeAnnotation}s
|
||||
* using only the ones they need.
|
||||
*/
|
||||
public static class Builder extends ExpectedTypeAnnotation.Builder {
|
||||
protected final String fieldname;
|
||||
|
||||
/**
|
||||
* Create a {@code Builder} from the mandatory parameters.
|
||||
*
|
||||
* @param fieldname The expected field name.
|
||||
* @param expectedName The expected annotation name.
|
||||
* @param targetType The expected target type.
|
||||
* @param visibility Whether this annotation should be runtime-visible.
|
||||
* @param expectedCount The number of annotations that should be seen.
|
||||
*/
|
||||
public Builder(String fieldname,
|
||||
String expectedName,
|
||||
TypeAnnotation.TargetType targetType,
|
||||
boolean visibility,
|
||||
int expectedCount) {
|
||||
super(expectedName, targetType, visibility, expectedCount);
|
||||
this.fieldname = fieldname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@code ExpectedFieldTypeAnnotation} from all
|
||||
* parameters that have been provided. The default values
|
||||
* will be used for those that have not.
|
||||
*
|
||||
* @return The cretaed {@code ExpectedFieldTypeAnnotation}.
|
||||
*/
|
||||
public ExpectedFieldTypeAnnotation build() {
|
||||
return new ExpectedFieldTypeAnnotation(fieldname, expectedName,
|
||||
visibility, expectedCount,
|
||||
targetType, bound_index,
|
||||
parameter_index, type_index,
|
||||
exception_index, typePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void matchClassTypeAnnotation(ClassFile classfile,
|
||||
ExpectedTypeAnnotation expected)
|
||||
throws ConstantPoolException {
|
||||
for(Attribute attr : classfile.attributes) {
|
||||
attr.accept(typeAnnoMatcher, expected);
|
||||
}
|
||||
}
|
||||
|
||||
private void matchMethodTypeAnnotation(ClassFile classfile,
|
||||
ExpectedMethodTypeAnnotation expected)
|
||||
throws ConstantPoolException {
|
||||
for(Method meth : classfile.methods) {
|
||||
if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
|
||||
for(Attribute attr : meth.attributes) {
|
||||
attr.accept(typeAnnoMatcher, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void matchFieldTypeAnnotation(ClassFile classfile,
|
||||
ExpectedFieldTypeAnnotation expected)
|
||||
throws ConstantPoolException {
|
||||
for(Field field : classfile.fields) {
|
||||
if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
|
||||
for(Attribute attr : field.attributes) {
|
||||
attr.accept(typeAnnoMatcher, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void matchClassTypeAnnotations(ClassFile classfile,
|
||||
ExpectedTypeAnnotation[] expected)
|
||||
throws ConstantPoolException {
|
||||
for(ExpectedTypeAnnotation one : expected) {
|
||||
matchClassTypeAnnotation(classfile, one);
|
||||
}
|
||||
}
|
||||
|
||||
private void matchMethodTypeAnnotations(ClassFile classfile,
|
||||
ExpectedMethodTypeAnnotation[] expected)
|
||||
throws ConstantPoolException {
|
||||
for(ExpectedMethodTypeAnnotation one : expected) {
|
||||
matchMethodTypeAnnotation(classfile, one);
|
||||
}
|
||||
}
|
||||
|
||||
private void matchFieldTypeAnnotations(ClassFile classfile,
|
||||
ExpectedFieldTypeAnnotation[] expected)
|
||||
throws ConstantPoolException {
|
||||
for(ExpectedFieldTypeAnnotation one : expected) {
|
||||
matchFieldTypeAnnotation(classfile, one);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a template on a single {@code ClassFile}.
|
||||
*
|
||||
* @param classfile The {@code ClassFile} on which to run tests.
|
||||
* @param expected The expected annotation template.
|
||||
*/
|
||||
public void run(ClassFile classfile,
|
||||
Expected... expected)
|
||||
throws ConstantPoolException {
|
||||
run(new ClassFile[] { classfile }, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a template on multiple {@code ClassFile}s.
|
||||
*
|
||||
* @param classfile The {@code ClassFile}s on which to run tests.
|
||||
* @param expected The expected annotation template.
|
||||
*/
|
||||
public void run(ClassFile[] classfiles,
|
||||
Expected... expected)
|
||||
throws ConstantPoolException {
|
||||
for(ClassFile classfile : classfiles) {
|
||||
for(Expected one : expected) {
|
||||
if (one.matchClassName(classfile.getName())) {
|
||||
if (one.classAnnos != null)
|
||||
matchClassTypeAnnotations(classfile, one.classAnnos);
|
||||
if (one.methodAnnos != null)
|
||||
matchMethodTypeAnnotations(classfile, one.methodAnnos);
|
||||
if (one.fieldAnnos != null)
|
||||
matchFieldTypeAnnotations(classfile, one.fieldAnnos);
|
||||
}
|
||||
}
|
||||
}
|
||||
int count = 0;
|
||||
for (Expected one : expected) {
|
||||
count += one.check();
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
throw new RuntimeException(count + " errors occurred in test");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code ClassFile} from its file name.
|
||||
*
|
||||
* @param name The class' file name.
|
||||
* @return The {@code ClassFile}
|
||||
*/
|
||||
public static ClassFile getClassFile(String name)
|
||||
throws IOException, ConstantPoolException {
|
||||
final URL url = ClassfileInspector.class.getResource(name);
|
||||
final InputStream in = url.openStream();
|
||||
try {
|
||||
return ClassFile.read(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Attribute.Visitor<Void, ExpectedTypeAnnotation> typeAnnoMatcher =
|
||||
new Attribute.Visitor<Void, ExpectedTypeAnnotation>() {
|
||||
|
||||
@Override
|
||||
public Void visitBootstrapMethods(BootstrapMethods_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitDefault(DefaultAttribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitAnnotationDefault(AnnotationDefault_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCode(Code_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCompilationID(CompilationID_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitConstantValue(ConstantValue_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitDeprecated(Deprecated_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitEnclosingMethod(EnclosingMethod_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitExceptions(Exceptions_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitInnerClasses(InnerClasses_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLineNumberTable(LineNumberTable_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLocalVariableTable(LocalVariableTable_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitMethodParameters(MethodParameters_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSignature(Signature_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSourceFile(SourceFile_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSourceID(SourceID_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitStackMap(StackMap_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitStackMapTable(StackMapTable_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSynthetic(Synthetic_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
if (expected.matchVisibility(true)) {
|
||||
for(TypeAnnotation anno : attr.annotations) {
|
||||
expected.matchAnnotation(anno);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr,
|
||||
ExpectedTypeAnnotation expected) {
|
||||
if (expected.matchVisibility(false)) {
|
||||
for(TypeAnnotation anno : attr.annotations) {
|
||||
expected.matchAnnotation(anno);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test SyntheticParameters
|
||||
* @summary Test generation of annotations on inner class parameters.
|
||||
* @build ClassfileInspector
|
||||
* @run main SyntheticParameters
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
|
||||
public class SyntheticParameters extends ClassfileInspector {
|
||||
|
||||
private static final String Inner_class = "SyntheticParameters$Inner.class";
|
||||
private static final String Foo_class = "SyntheticParameters$Foo.class";
|
||||
private static final Expected Inner_expected =
|
||||
new Expected("SyntheticParameters$Inner",
|
||||
null,
|
||||
new ExpectedMethodTypeAnnotation[] {
|
||||
(ExpectedMethodTypeAnnotation)
|
||||
// Assert there is no annotation on the
|
||||
// this$0 parameter.
|
||||
new ExpectedMethodTypeAnnotation.Builder(
|
||||
"<init>",
|
||||
"A",
|
||||
TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
|
||||
false,
|
||||
0).setParameterIndex(0).build(),
|
||||
(ExpectedMethodTypeAnnotation)
|
||||
// Assert there is an annotation on the
|
||||
// first parameter.
|
||||
new ExpectedMethodTypeAnnotation.Builder(
|
||||
"<init>",
|
||||
"A",
|
||||
TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
|
||||
false,
|
||||
1).setParameterIndex(1).build(),
|
||||
(ExpectedMethodTypeAnnotation)
|
||||
new ExpectedMethodTypeAnnotation.Builder(
|
||||
"foo",
|
||||
"A",
|
||||
TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
|
||||
false,
|
||||
1).setParameterIndex(0).build(),
|
||||
(ExpectedMethodTypeAnnotation)
|
||||
new ExpectedMethodTypeAnnotation.Builder(
|
||||
"foo",
|
||||
"A",
|
||||
TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
|
||||
false,
|
||||
0).setParameterIndex(1).build()
|
||||
},
|
||||
null);
|
||||
private static final Expected Foo_expected =
|
||||
new Expected("SyntheticParameters$Foo",
|
||||
null,
|
||||
new ExpectedMethodTypeAnnotation[] {
|
||||
(ExpectedMethodTypeAnnotation)
|
||||
// Assert there is no annotation on the
|
||||
// $enum$name parameter.
|
||||
new ExpectedMethodTypeAnnotation.Builder(
|
||||
"<init>",
|
||||
"A",
|
||||
TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
|
||||
false,
|
||||
0).setParameterIndex(0).build(),
|
||||
(ExpectedMethodTypeAnnotation)
|
||||
// Assert there is no annotation on the
|
||||
// $enum$ordinal parameter.
|
||||
new ExpectedMethodTypeAnnotation.Builder(
|
||||
"<init>",
|
||||
"A",
|
||||
TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
|
||||
false,
|
||||
0).setParameterIndex(1).build(),
|
||||
(ExpectedMethodTypeAnnotation)
|
||||
// Assert there is an annotation on the
|
||||
// first parameter.
|
||||
new ExpectedMethodTypeAnnotation.Builder(
|
||||
"<init>",
|
||||
"A",
|
||||
TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
|
||||
false,
|
||||
1).setParameterIndex(2).build()
|
||||
},
|
||||
null);
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
new SyntheticParameters().run(
|
||||
new ClassFile[] { getClassFile(Inner_class), getClassFile(Foo_class) },
|
||||
new Expected[] { Inner_expected, Foo_expected });
|
||||
}
|
||||
|
||||
public class Inner {
|
||||
public Inner(@A int a) {}
|
||||
public void foo(@A int a, int b) {}
|
||||
}
|
||||
|
||||
public static enum Foo {
|
||||
ONE(null);
|
||||
Foo(@A Object a) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface A {}
|
@ -43,7 +43,7 @@ public class Constructors {
|
||||
|
||||
@TADescription(annotation = "TA", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "TB", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "TC", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
|
||||
@TADescription(annotation = "TC", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
|
||||
@TestClass("%TEST_CLASS_NAME%$Inner")
|
||||
public String innerClass() {
|
||||
return "class %TEST_CLASS_NAME% { class Inner {" +
|
||||
@ -56,7 +56,7 @@ public class Constructors {
|
||||
@TADescription(annotation = "TB", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "TC", type = METHOD_RECEIVER)
|
||||
@TADescription(annotation = "TD", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "TE", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
|
||||
@TADescription(annotation = "TE", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
|
||||
@TestClass("%TEST_CLASS_NAME%$Inner")
|
||||
public String innerClass2() {
|
||||
return "class %TEST_CLASS_NAME% { class Inner {" +
|
||||
@ -70,7 +70,7 @@ public class Constructors {
|
||||
@TADescription(annotation = "TC", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
|
||||
@TADescription(annotation = "TD", type = METHOD_RECEIVER, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "TE", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
|
||||
@TADescription(annotation = "TF", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
|
||||
@TADescription(annotation = "TF", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
|
||||
@TestClass("Outer$Middle$Inner")
|
||||
public String innerClass3() {
|
||||
return "class Outer { class Middle { class Inner {" +
|
||||
@ -89,7 +89,7 @@ public class Constructors {
|
||||
|
||||
@TADescription(annotation = "RTAs", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "RTBs", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "RTCs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
|
||||
@TADescription(annotation = "RTCs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
|
||||
@TestClass("%TEST_CLASS_NAME%$Inner")
|
||||
public String innerClassRepeatableAnnotation() {
|
||||
return "class %TEST_CLASS_NAME% { class Inner {" +
|
||||
@ -102,7 +102,7 @@ public class Constructors {
|
||||
@TADescription(annotation = "RTBs", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "RTCs", type = METHOD_RECEIVER)
|
||||
@TADescription(annotation = "RTDs", type = METHOD_RETURN, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "RTEs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
|
||||
@TADescription(annotation = "RTEs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
|
||||
@TestClass("%TEST_CLASS_NAME%$Inner")
|
||||
public String innerClassRepeatableAnnotation2() {
|
||||
return "class %TEST_CLASS_NAME% { class Inner {" +
|
||||
@ -116,7 +116,7 @@ public class Constructors {
|
||||
@TADescription(annotation = "RTCs", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
|
||||
@TADescription(annotation = "RTDs", type = METHOD_RECEIVER, genericLocation = {1, 0})
|
||||
@TADescription(annotation = "RTEs", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
|
||||
@TADescription(annotation = "RTFs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
|
||||
@TADescription(annotation = "RTFs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
|
||||
@TestClass("Outer$Middle$Inner")
|
||||
public String innerClassRepatableAnnotation3() {
|
||||
return "class Outer { class Middle { class Inner {" +
|
||||
|
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8042931
|
||||
* @summary Checking EnclosingMethod attribute of anonymous/local class.
|
||||
* @library /tools/lib /tools/javac/lib ../lib
|
||||
* @build EnclosingMethodTest TestBase TestResult InMemoryFileManager ToolBox
|
||||
* @run main EnclosingMethodTest
|
||||
*/
|
||||
|
||||
import com.sun.tools.classfile.Attribute;
|
||||
import com.sun.tools.classfile.ClassFile;
|
||||
import com.sun.tools.classfile.EnclosingMethod_attribute;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The test checks the enclosing method attribute of anonymous/local classes.
|
||||
* The top-level class contains the anonymous and local classes to be tested. The test examines
|
||||
* each inner class and determine whether the class should have the EnclosingMethod attribute or not.
|
||||
* Golden information about enclosing methods are held in annotation {@code ExpectedEnclosingMethod}.
|
||||
*
|
||||
* The test assumes that a class must have the EnclosingMethod attribute if the class is annotated or
|
||||
* if its parent class is annotated in case of anonymous class. In addition, classes
|
||||
* named {@code VariableInitializer} are introduced to test variable initializer cases. These classes
|
||||
* must not have the enclosing method attribute, but its anonymous derived class must.
|
||||
* After classification of classes, the test checks whether classes contain the correct enclosing
|
||||
* method attribute in case of anonymous/local class, or checks whether classes do not contain
|
||||
* the EnclosingMethod attribute, otherwise.
|
||||
*
|
||||
* Test cases:
|
||||
* top-level class as enclosing class:
|
||||
* 1. anonymous and local classes in static initializer;
|
||||
* 2. anonymous and local classes in instance initializer;
|
||||
* 3. anonymous and local classes in lambda;
|
||||
* 4. anonymous and local classes in constructor;
|
||||
* 5. anonymous and local classes in method;
|
||||
* 6. static and instance variable initializer.
|
||||
*
|
||||
* inner class as enclosing class:
|
||||
* 1. anonymous and local classes in static initializer;
|
||||
* 2. anonymous and local classes in instance initializer;
|
||||
* 3. anonymous and local classes in lambda;
|
||||
* 4. anonymous and local classes in constructor;
|
||||
* 5. anonymous and local classes in method;
|
||||
* 6. static and instance variable initializer.
|
||||
*
|
||||
* enum as enclosing class:
|
||||
* 1. anonymous and local classes in static initializer;
|
||||
* 2. anonymous and local classes in instance initializer;
|
||||
* 3. anonymous and local classes in lambda;
|
||||
* 4. anonymous and local classes in constructor;
|
||||
* 5. anonymous and local classes in method;
|
||||
* 6. static and instance variable initializer.
|
||||
*
|
||||
* interface as enclosing class:
|
||||
* 1. anonymous and local classes in lambda;
|
||||
* 2. anonymous and local classes in static method;
|
||||
* 3. anonymous and local classes in default method;
|
||||
* 4. static variable initializer.
|
||||
*
|
||||
* annotation as enclosing class:
|
||||
* 1. anonymous and local classes in lambda;
|
||||
* 2. static variable initializer.
|
||||
*/
|
||||
public class EnclosingMethodTest extends TestResult {
|
||||
|
||||
private final Map<Class<?>, ExpectedEnclosingMethod> class2EnclosingMethod = new HashMap<>();
|
||||
private final Set<Class<?>> noEnclosingMethod = new HashSet<>();
|
||||
|
||||
public EnclosingMethodTest() throws ClassNotFoundException {
|
||||
Class<EnclosingMethodTest> outerClass = EnclosingMethodTest.class;
|
||||
String outerClassName = outerClass.getSimpleName();
|
||||
File testClasses = getClassDir();
|
||||
FilenameFilter filter = (dir, name) -> name.matches(outerClassName + ".*\\.class");
|
||||
|
||||
for (File file : testClasses.listFiles(filter)) {
|
||||
Class<?> clazz = Class.forName(file.getName().replace(".class", ""));
|
||||
if (clazz.isAnonymousClass()) {
|
||||
// anonymous class cannot be annotated, information is in its parent class.
|
||||
ExpectedEnclosingMethod declaredAnnotation =
|
||||
clazz.getSuperclass().getDeclaredAnnotation(ExpectedEnclosingMethod.class);
|
||||
class2EnclosingMethod.put(clazz, declaredAnnotation);
|
||||
} else {
|
||||
ExpectedEnclosingMethod enclosingMethod = clazz.getDeclaredAnnotation(ExpectedEnclosingMethod.class);
|
||||
// if class is annotated and it does not contain information for variable initializer cases,
|
||||
// then it must have the enclosing method attribute.
|
||||
if (enclosingMethod != null && !clazz.getSimpleName().contains("VariableInitializer")) {
|
||||
class2EnclosingMethod.put(clazz, enclosingMethod);
|
||||
} else {
|
||||
noEnclosingMethod.add(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void test() throws TestFailedException {
|
||||
try {
|
||||
testEnclosingMethodAttribute();
|
||||
testLackOfEnclosingMethodAttribute();
|
||||
} finally {
|
||||
checkStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void testLackOfEnclosingMethodAttribute() {
|
||||
for (Class<?> clazz : noEnclosingMethod) {
|
||||
try {
|
||||
addTestCase("Class should not have EnclosingMethod attribute : " + clazz);
|
||||
ClassFile classFile = readClassFile(clazz);
|
||||
checkEquals(countEnclosingMethodAttributes(classFile),
|
||||
0l, "number of the EnclosingMethod attribute in the class is zero : "
|
||||
+ classFile.getName());
|
||||
} catch (Exception e) {
|
||||
addFailure(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void testEnclosingMethodAttribute() {
|
||||
class2EnclosingMethod.forEach((clazz, enclosingMethod) -> {
|
||||
try {
|
||||
String info = enclosingMethod.info() + " "
|
||||
+ (clazz.isAnonymousClass() ? "anonymous" : "local");
|
||||
addTestCase(info);
|
||||
printf("Testing test case : %s\n", info);
|
||||
ClassFile classFile = readClassFile(clazz);
|
||||
String className = clazz.getName();
|
||||
checkEquals(countEnclosingMethodAttributes(classFile), 1l,
|
||||
"number of the EnclosingMethod attribute in the class is one : "
|
||||
+ clazz);
|
||||
EnclosingMethod_attribute attr = (EnclosingMethod_attribute)
|
||||
classFile.getAttribute(Attribute.EnclosingMethod);
|
||||
|
||||
if (!checkNotNull(attr, "the EnclosingMethod attribute is not null : " + className)) {
|
||||
// stop checking, attr is null. test case failed
|
||||
return;
|
||||
}
|
||||
checkEquals(classFile.constant_pool.getUTF8Value(attr.attribute_name_index),
|
||||
"EnclosingMethod",
|
||||
"attribute_name_index of EnclosingMethod attribute in the class : " + className);
|
||||
checkEquals(attr.attribute_length, 4,
|
||||
"attribute_length of EnclosingMethod attribute in the class : " + className);
|
||||
String expectedClassName = enclosingMethod.enclosingClazz().getName();
|
||||
checkEquals(classFile.constant_pool.getClassInfo(attr.class_index).getName(),
|
||||
expectedClassName, String.format(
|
||||
"enclosing class of EnclosingMethod attribute in the class %s is %s",
|
||||
className, expectedClassName));
|
||||
|
||||
String expectedMethodName = enclosingMethod.enclosingMethod();
|
||||
if (expectedMethodName.isEmpty()) {
|
||||
// class does not have an enclosing method
|
||||
checkEquals(attr.method_index, 0, String.format(
|
||||
"enclosing method of EnclosingMethod attribute in the class %s is null", className));
|
||||
} else {
|
||||
String methodName = classFile.constant_pool.getNameAndTypeInfo(attr.method_index).getName();
|
||||
checkTrue(methodName.startsWith(expectedMethodName), String.format(
|
||||
"enclosing method of EnclosingMethod attribute in the class %s" +
|
||||
" is method name %s" +
|
||||
", actual method name is %s",
|
||||
className, expectedMethodName, methodName));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
addFailure(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private long countEnclosingMethodAttributes(ClassFile classFile) {
|
||||
return Stream.of(classFile.attributes.attrs)
|
||||
.filter(x -> x instanceof EnclosingMethod_attribute)
|
||||
.count();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExpectedEnclosingMethod {
|
||||
String info();
|
||||
Class<?> enclosingClazz();
|
||||
String enclosingMethod() default "";
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException, TestFailedException {
|
||||
new EnclosingMethodTest().test();
|
||||
}
|
||||
|
||||
// Test cases: enclosing class is a top-level class
|
||||
static {
|
||||
// anonymous and local classes in static initializer
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingStaticInitialization in EnclosingMethodTest",
|
||||
enclosingClazz = EnclosingMethodTest.class
|
||||
)
|
||||
class EnclosingStaticInitialization {
|
||||
}
|
||||
new EnclosingStaticInitialization() {
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// anonymous and local classes in instance initializer
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingInitialization in EnclosingMethodTest",
|
||||
enclosingClazz = EnclosingMethodTest.class
|
||||
)
|
||||
class EnclosingInitialization {
|
||||
}
|
||||
new EnclosingInitialization() {
|
||||
};
|
||||
}
|
||||
|
||||
Runnable lambda = () -> {
|
||||
// anonymous and local classes in lambda
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingLambda in EnclosingMethodTest",
|
||||
enclosingMethod = "lambda",
|
||||
enclosingClazz = EnclosingMethodTest.class
|
||||
)
|
||||
class EnclosingLambda {
|
||||
}
|
||||
new EnclosingLambda() {
|
||||
};
|
||||
};
|
||||
|
||||
EnclosingMethodTest(int i) {
|
||||
// anonymous and local classes in constructor
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingConstructor in EnclosingMethodTest",
|
||||
enclosingMethod = "<init>",
|
||||
enclosingClazz = EnclosingMethodTest.class
|
||||
)
|
||||
class EnclosingConstructor {
|
||||
}
|
||||
new EnclosingConstructor() {
|
||||
};
|
||||
}
|
||||
|
||||
void method() {
|
||||
// anonymous and local classes in method
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingMethod in EnclosingMethodTest",
|
||||
enclosingMethod = "method",
|
||||
enclosingClazz = EnclosingMethodTest.class
|
||||
)
|
||||
class EnclosingMethod {
|
||||
}
|
||||
new EnclosingMethod() {
|
||||
};
|
||||
}
|
||||
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "VariableInitializer in EnclosingMethodTest",
|
||||
enclosingClazz = EnclosingMethodTest.class
|
||||
)
|
||||
static class VariableInitializer {
|
||||
}
|
||||
|
||||
// static variable initializer
|
||||
private static final VariableInitializer cvi = new VariableInitializer() {
|
||||
};
|
||||
|
||||
// instance variable initializer
|
||||
private final VariableInitializer ivi = new VariableInitializer() {
|
||||
};
|
||||
|
||||
// Test cases: enclosing class is an inner class
|
||||
public static class notEnclosing01 {
|
||||
static {
|
||||
// anonymous and local classes in static initializer
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingStaticInitialization in notEnclosing01",
|
||||
enclosingClazz = notEnclosing01.class
|
||||
)
|
||||
class EnclosingStaticInitialization {
|
||||
}
|
||||
new EnclosingStaticInitialization() {
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// anonymous and local classes in instance initializer
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingInitialization in notEnclosing01",
|
||||
enclosingClazz = notEnclosing01.class
|
||||
)
|
||||
class EnclosingInitialization {
|
||||
}
|
||||
new EnclosingInitialization() {
|
||||
};
|
||||
}
|
||||
|
||||
Runnable lambda = () -> {
|
||||
// anonymous and local classes in lambda
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingLambda in notEnclosing01",
|
||||
enclosingMethod = "lambda",
|
||||
enclosingClazz = notEnclosing01.class
|
||||
)
|
||||
class EnclosingLambda {
|
||||
}
|
||||
new EnclosingLambda() {
|
||||
};
|
||||
};
|
||||
|
||||
notEnclosing01() {
|
||||
// anonymous and local classes in constructor
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingConstructor in notEnclosing01",
|
||||
enclosingMethod = "<init>",
|
||||
enclosingClazz = notEnclosing01.class
|
||||
)
|
||||
class EnclosingConstructor {
|
||||
}
|
||||
new EnclosingConstructor() {
|
||||
};
|
||||
}
|
||||
|
||||
void method() {
|
||||
// anonymous and local classes in method
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingMethod in notEnclosing01",
|
||||
enclosingMethod = "method",
|
||||
enclosingClazz = notEnclosing01.class
|
||||
)
|
||||
class EnclosingMethod {
|
||||
}
|
||||
new EnclosingMethod() {
|
||||
};
|
||||
}
|
||||
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "VariableInitializer in notEnclosing01",
|
||||
enclosingClazz = notEnclosing01.class
|
||||
)
|
||||
static class VariableInitializer {
|
||||
}
|
||||
|
||||
// static variable initializer
|
||||
private static final VariableInitializer cvi = new VariableInitializer() {
|
||||
};
|
||||
|
||||
// instance variable initializer
|
||||
private final VariableInitializer ivi = new VariableInitializer() {
|
||||
};
|
||||
}
|
||||
|
||||
// Test cases: enclosing class is an interface
|
||||
public interface notEnclosing02 {
|
||||
Runnable lambda = () -> {
|
||||
// anonymous and local classes in lambda
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingLambda in notEnclosing02",
|
||||
enclosingMethod = "lambda",
|
||||
enclosingClazz = notEnclosing02.class
|
||||
)
|
||||
class EnclosingLambda {
|
||||
}
|
||||
new EnclosingLambda() {
|
||||
};
|
||||
};
|
||||
|
||||
static void staticMethod() {
|
||||
// anonymous and local classes in static method
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingMethod in notEnclosing02",
|
||||
enclosingMethod = "staticMethod",
|
||||
enclosingClazz = notEnclosing02.class
|
||||
)
|
||||
class EnclosingMethod {
|
||||
}
|
||||
new EnclosingMethod() {
|
||||
};
|
||||
}
|
||||
|
||||
default void defaultMethod() {
|
||||
// anonymous and local classes in default method
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingMethod in notEnclosing02",
|
||||
enclosingMethod = "defaultMethod",
|
||||
enclosingClazz = notEnclosing02.class
|
||||
)
|
||||
class EnclosingMethod {
|
||||
}
|
||||
new EnclosingMethod() {
|
||||
};
|
||||
}
|
||||
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "VariableInitializer in notEnclosing02",
|
||||
enclosingClazz = notEnclosing02.class
|
||||
)
|
||||
static class VariableInitializer {
|
||||
}
|
||||
|
||||
// static variable initializer
|
||||
VariableInitializer cvi = new VariableInitializer() {
|
||||
};
|
||||
}
|
||||
|
||||
// Test cases: enclosing class is an enum
|
||||
public enum notEnclosing03 {;
|
||||
|
||||
static {
|
||||
// anonymous and local classes in static initializer
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingStaticInitialization in notEnclosing03",
|
||||
enclosingClazz = notEnclosing03.class
|
||||
)
|
||||
class EnclosingStaticInitialization {
|
||||
}
|
||||
new EnclosingStaticInitialization() {
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// anonymous and local classes in instance initializer
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingInitialization in notEnclosing03",
|
||||
enclosingClazz = notEnclosing03.class
|
||||
)
|
||||
class EnclosingInitialization {
|
||||
}
|
||||
new EnclosingInitialization() {
|
||||
};
|
||||
}
|
||||
|
||||
Runnable lambda = () -> {
|
||||
// anonymous and local classes in lambda
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingLambda in notEnclosing03",
|
||||
enclosingMethod = "lambda",
|
||||
enclosingClazz = notEnclosing03.class
|
||||
)
|
||||
class EnclosingLambda {
|
||||
}
|
||||
new EnclosingLambda() {
|
||||
};
|
||||
};
|
||||
|
||||
notEnclosing03() {
|
||||
// anonymous and local classes in constructor
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingConstructor in notEnclosing03",
|
||||
enclosingMethod = "<init>",
|
||||
enclosingClazz = notEnclosing03.class
|
||||
)
|
||||
class EnclosingConstructor {
|
||||
}
|
||||
new EnclosingConstructor() {
|
||||
};
|
||||
}
|
||||
|
||||
void method() {
|
||||
// anonymous and local classes in method
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingMethod in notEnclosing03",
|
||||
enclosingMethod = "method",
|
||||
enclosingClazz = notEnclosing03.class
|
||||
)
|
||||
class EnclosingMethod {
|
||||
}
|
||||
new EnclosingMethod() {
|
||||
};
|
||||
}
|
||||
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "VariableInitializer in notEnclosing03",
|
||||
enclosingClazz = notEnclosing03.class
|
||||
)
|
||||
static class VariableInitializer {
|
||||
}
|
||||
|
||||
// static variable initializer
|
||||
private static final VariableInitializer cvi = new VariableInitializer() {
|
||||
};
|
||||
|
||||
// instance variable initializer
|
||||
private final VariableInitializer ivi = new VariableInitializer() {
|
||||
};
|
||||
}
|
||||
|
||||
// Test cases: enclosing class is an annotation
|
||||
public @interface notEnclosing04 {
|
||||
Runnable lambda = () -> {
|
||||
// anonymous and local classes in lambda
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "EnclosingLambda in notEnclosing04",
|
||||
enclosingMethod = "lambda",
|
||||
enclosingClazz = notEnclosing04.class
|
||||
)
|
||||
class EnclosingLambda {
|
||||
}
|
||||
new EnclosingLambda() {
|
||||
};
|
||||
};
|
||||
|
||||
@ExpectedEnclosingMethod(
|
||||
info = "VariableInitializer in notEnclosing04",
|
||||
enclosingClazz = notEnclosing04.class
|
||||
)
|
||||
static class VariableInitializer {
|
||||
}
|
||||
|
||||
// static variable initializer
|
||||
VariableInitializer cvi = new VariableInitializer() {
|
||||
};
|
||||
}
|
||||
}
|
@ -74,13 +74,13 @@ public class DeprecatedPackageTest extends TestResult {
|
||||
addTestCase(src);
|
||||
printf("Testing test case: \n%s\n", src);
|
||||
try {
|
||||
ClassFile cf = ClassFile.read(compile(
|
||||
ClassFile cf = readClassFile(compile(
|
||||
new String[]{"package-info.java", package_info},
|
||||
new String[]{"notDeprecated.java", src})
|
||||
.getClasses().get(CLASS_NAME).openInputStream());
|
||||
.getClasses().get(CLASS_NAME));
|
||||
Deprecated_attribute attr =
|
||||
(Deprecated_attribute) cf.getAttribute(Attribute.Deprecated);
|
||||
assertNull(attr, "Class can not have deprecated attribute : " + CLASS_NAME);
|
||||
checkNull(attr, "Class can not have deprecated attribute : " + CLASS_NAME);
|
||||
} catch (Exception e) {
|
||||
addFailure(e);
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ public class DeprecatedTest extends TestResult {
|
||||
? "deprecated"
|
||||
: "notDeprecated";
|
||||
echo("Testing outer class : " + outerClassName);
|
||||
ClassFile cf = ClassFile.read(classes.get(outerClassName).openInputStream());
|
||||
ClassFile cf = readClassFile(classes.get(outerClassName));
|
||||
Deprecated_attribute attr = (Deprecated_attribute)
|
||||
cf.getAttribute(Attribute.Deprecated);
|
||||
testAttribute(outerClassName, attr, cf);
|
||||
@ -260,7 +260,7 @@ public class DeprecatedTest extends TestResult {
|
||||
String innerClassName = cf.constant_pool.
|
||||
getClassInfo(innerClass.inner_class_info_index).getName();
|
||||
echo("Testing inner class : " + innerClassName);
|
||||
ClassFile innerCf = ClassFile.read(classes.get(innerClassName).openInputStream());
|
||||
ClassFile innerCf = readClassFile(classes.get(innerClassName));
|
||||
Deprecated_attribute attr = (Deprecated_attribute)
|
||||
innerCf.getAttribute(Attribute.Deprecated);
|
||||
String innerClassSimpleName = innerClass.getInnerName(cf.constant_pool);
|
||||
@ -298,17 +298,18 @@ public class DeprecatedTest extends TestResult {
|
||||
if (name.contains("deprecated")) {
|
||||
testDeprecatedAttribute(name, attr, cf);
|
||||
} else {
|
||||
assertNull(attr, name + " should not have deprecated attribute");
|
||||
checkNull(attr, name + " should not have deprecated attribute");
|
||||
}
|
||||
}
|
||||
|
||||
private void testDeprecatedAttribute(String name, Deprecated_attribute attr, ClassFile cf)
|
||||
throws ConstantPoolException {
|
||||
assertNotNull(attr, name + " must have deprecated attribute");
|
||||
assertEquals(0, attr.attribute_length,
|
||||
"attribute_length should equal to 0");
|
||||
assertEquals("Deprecated",
|
||||
cf.constant_pool.getUTF8Value(attr.attribute_name_index),
|
||||
name + " attribute_name_index");
|
||||
if (checkNotNull(attr, name + " must have deprecated attribute")) {
|
||||
checkEquals(0, attr.attribute_length,
|
||||
"attribute_length should equal to 0");
|
||||
checkEquals("Deprecated",
|
||||
cf.constant_pool.getUTF8Value(attr.attribute_name_index),
|
||||
name + " attribute_name_index");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,21 +96,21 @@ public class InnerClassesHierarchyTest extends TestResult {
|
||||
ClassFile cf = readClassFile(currentClassName);
|
||||
InnerClasses_attribute attr = (InnerClasses_attribute)
|
||||
cf.getAttribute(Attribute.InnerClasses);
|
||||
assertNotNull(attr, "Class should not contain "
|
||||
checkNotNull(attr, "Class should not contain "
|
||||
+ "inner classes attribute : " + currentClassName);
|
||||
assertTrue(innerClasses.containsKey(currentClassName),
|
||||
checkTrue(innerClasses.containsKey(currentClassName),
|
||||
"map contains class name : " + currentClassName);
|
||||
Set<String> setClasses = innerClasses.get(currentClassName);
|
||||
if (setClasses == null) {
|
||||
continue;
|
||||
}
|
||||
assertEquals(attr.number_of_classes,
|
||||
checkEquals(attr.number_of_classes,
|
||||
setClasses.size(),
|
||||
"Check number of inner classes : " + setClasses);
|
||||
for (Info info : attr.classes) {
|
||||
String innerClassName = info
|
||||
.getInnerClassInfo(cf.constant_pool).getBaseName();
|
||||
assertTrue(setClasses.contains(innerClassName),
|
||||
checkTrue(setClasses.contains(innerClassName),
|
||||
currentClassName + " contains inner class : "
|
||||
+ innerClassName);
|
||||
if (visitedClasses.add(innerClassName)) {
|
||||
@ -124,10 +124,10 @@ public class InnerClassesHierarchyTest extends TestResult {
|
||||
|
||||
Set<String> a_b = removeAll(visitedClasses, allClasses);
|
||||
Set<String> b_a = removeAll(allClasses, visitedClasses);
|
||||
assertEquals(visitedClasses, allClasses,
|
||||
checkEquals(visitedClasses, allClasses,
|
||||
"All classes are found\n"
|
||||
+ "visited - all classes : " + a_b
|
||||
+ "\nall classes - visited : " + b_a);
|
||||
+ "visited - all classes : " + a_b
|
||||
+ "\nall classes - visited : " + b_a);
|
||||
} catch (Exception e) {
|
||||
addFailure(e);
|
||||
} finally {
|
||||
|
@ -78,16 +78,16 @@ public class InnerClassesIndexTest extends TestResult {
|
||||
continue;
|
||||
}
|
||||
foundClasses.add(innerName);
|
||||
assertEquals(info.outer_class_info_index, 0,
|
||||
checkEquals(info.outer_class_info_index, 0,
|
||||
"outer_class_info_index of " + innerName);
|
||||
if (innerName.matches("\\$\\d+")) {
|
||||
assertEquals(info.inner_name_index, 0,
|
||||
checkEquals(info.inner_name_index, 0,
|
||||
"inner_name_index of anonymous class");
|
||||
}
|
||||
}
|
||||
Set<String> expectedClasses = getInnerClasses();
|
||||
expectedClasses.remove("InnerClassesIndexTest$Inner");
|
||||
assertEquals(foundClasses, expectedClasses, "All classes are found");
|
||||
checkEquals(foundClasses, expectedClasses, "All classes are found");
|
||||
} catch (Exception e) {
|
||||
addFailure(e);
|
||||
} finally {
|
||||
|
@ -202,44 +202,44 @@ public abstract class InnerClassesTestBase extends TestResult {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
assertEquals(1, count, "Number of inner classes attribute");
|
||||
if (innerClasses == null) {
|
||||
checkEquals(1, count, "Number of inner classes attribute");
|
||||
if (!checkNotNull(innerClasses, "InnerClasses attribute should not be null")) {
|
||||
return;
|
||||
}
|
||||
assertEquals(cf.constant_pool.
|
||||
checkEquals(cf.constant_pool.
|
||||
getUTF8Info(innerClasses.attribute_name_index).value, "InnerClasses",
|
||||
"innerClasses.attribute_name_index");
|
||||
// Inner Classes attribute consists of length (2 bytes)
|
||||
// and 8 bytes for each inner class's entry.
|
||||
assertEquals(innerClasses.attribute_length,
|
||||
checkEquals(innerClasses.attribute_length,
|
||||
2 + 8 * class2Flags.size(), "innerClasses.attribute_length");
|
||||
assertEquals(innerClasses.number_of_classes,
|
||||
checkEquals(innerClasses.number_of_classes,
|
||||
class2Flags.size(), "innerClasses.number_of_classes");
|
||||
Set<String> visitedClasses = new HashSet<>();
|
||||
for (Info e : innerClasses.classes) {
|
||||
String baseName = cf.constant_pool.getClassInfo(
|
||||
e.inner_class_info_index).getBaseName();
|
||||
if (cf.major_version >= 51 && e.inner_name_index == 0) {
|
||||
assertEquals(e.outer_class_info_index, 0,
|
||||
"outer_class_info_index "
|
||||
+ "in case of inner_name_index is zero : "
|
||||
+ baseName);
|
||||
checkEquals(e.outer_class_info_index, 0,
|
||||
"outer_class_info_index "
|
||||
+ "in case of inner_name_index is zero : "
|
||||
+ baseName);
|
||||
}
|
||||
String className = baseName.replaceFirst(".*\\$", "");
|
||||
assertTrue(class2Flags.containsKey(className),
|
||||
checkTrue(class2Flags.containsKey(className),
|
||||
className);
|
||||
assertTrue(visitedClasses.add(className),
|
||||
checkTrue(visitedClasses.add(className),
|
||||
"there are no duplicates in attribute : " + className);
|
||||
assertEquals(e.inner_class_access_flags.getInnerClassFlags(),
|
||||
checkEquals(e.inner_class_access_flags.getInnerClassFlags(),
|
||||
class2Flags.get(className),
|
||||
"inner_class_access_flags " + className);
|
||||
if (!Arrays.asList(skipClasses).contains(className)) {
|
||||
assertEquals(
|
||||
cf.constant_pool.getClassInfo(e.inner_class_info_index).getBaseName(),
|
||||
classToTest + "$" + className,
|
||||
"inner_class_info_index of " + className);
|
||||
checkEquals(
|
||||
cf.constant_pool.getClassInfo(e.inner_class_info_index).getBaseName(),
|
||||
classToTest + "$" + className,
|
||||
"inner_class_info_index of " + className);
|
||||
if (e.outer_class_info_index > 0) {
|
||||
assertEquals(
|
||||
checkEquals(
|
||||
cf.constant_pool.getClassInfo(e.outer_class_info_index).getName(),
|
||||
classToTest,
|
||||
"outer_class_info_index of " + className);
|
||||
|
@ -25,10 +25,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -78,8 +75,8 @@ public class TestBase {
|
||||
/**
|
||||
* Compiles sources in memory.
|
||||
*
|
||||
* @param sources to compile.
|
||||
* @return memory file manager which contains class files and class loader.
|
||||
* @param sources to compile
|
||||
* @return in-memory file manager which contains class files and class loader
|
||||
*/
|
||||
public InMemoryFileManager compile(String... sources)
|
||||
throws IOException, CompilationException {
|
||||
@ -91,7 +88,7 @@ public class TestBase {
|
||||
*
|
||||
* @param options compiler options.
|
||||
* @param sources sources to compile.
|
||||
* @return map where key is className, value is corresponding ClassFile.
|
||||
* @return in-memory file manager which contains class files and class loader.
|
||||
*/
|
||||
public InMemoryFileManager compile(List<String> options, String... sources)
|
||||
throws IOException, CompilationException {
|
||||
@ -102,7 +99,7 @@ public class TestBase {
|
||||
* Compiles sources in memory.
|
||||
*
|
||||
* @param sources sources[i][0] - name of file, sources[i][1] - sources.
|
||||
* @return map where key is className, value is corresponding ClassFile.
|
||||
* @return in-memory file manager which contains class files and class loader.
|
||||
*/
|
||||
public InMemoryFileManager compile(String[]... sources) throws IOException,
|
||||
CompilationException {
|
||||
@ -114,7 +111,7 @@ public class TestBase {
|
||||
*
|
||||
* @param options compiler options
|
||||
* @param sources sources[i][0] - name of file, sources[i][1] - sources.
|
||||
* @return map where key is className, value is corresponding ClassFile.
|
||||
* @return in-memory file manager which contains class files and class loader.
|
||||
*/
|
||||
public InMemoryFileManager compile(List<String> options, String[]... sources)
|
||||
throws IOException, CompilationException {
|
||||
@ -142,7 +139,9 @@ public class TestBase {
|
||||
* @throws ConstantPoolException if constant pool error occurs
|
||||
*/
|
||||
public ClassFile readClassFile(JavaFileObject fileObject) throws IOException, ConstantPoolException {
|
||||
return readClassFile(fileObject.openInputStream());
|
||||
try (InputStream is = fileObject.openInputStream()) {
|
||||
return readClassFile(is);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,6 +204,12 @@ public class TestBase {
|
||||
assertEquals(actual, false, message);
|
||||
}
|
||||
|
||||
public void assertContains(Set<?> found, Set<?> expected, String message) {
|
||||
Set<?> copy = new HashSet<>(expected);
|
||||
copy.removeAll(found);
|
||||
assertTrue(found.containsAll(expected), message + " : " + copy);
|
||||
}
|
||||
|
||||
public File getSourceDir() {
|
||||
return new File(System.getProperty("test.src", "."));
|
||||
}
|
||||
|
@ -24,10 +24,7 @@
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This class accumulates test results. Test results can be checked with method @{code checkStatus}.
|
||||
@ -52,39 +49,46 @@ public class TestResult extends TestBase {
|
||||
|
||||
private String errorMessage() {
|
||||
return testCases.stream().filter(Info::isFailed)
|
||||
.map(tc -> format("Failure in test case:\n%s\n%s", tc.info(), tc.getMessage()))
|
||||
.collect(joining("\n"));
|
||||
.map(tc -> String.format("Failure in test case:\n%s\n%s", tc.info(), tc.getMessage()))
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertEquals(Object actual, Object expected, String message) {
|
||||
getLastTestCase().assertEquals(actual, expected, message);
|
||||
public boolean checkEquals(Object actual, Object expected, String message) {
|
||||
echo("Testing : " + message);
|
||||
if (!Objects.equals(actual, expected)) {
|
||||
getLastTestCase().addAssert(new AssertionFailedException(
|
||||
String.format("%s%nGot: %s, Expected: %s", message, actual, expected)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertNull(Object actual, String message) {
|
||||
getLastTestCase().assertEquals(actual, null, message);
|
||||
public boolean checkNull(Object actual, String message) {
|
||||
return checkEquals(actual, null, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertNotNull(Object actual, String message) {
|
||||
getLastTestCase().assertNotNull(actual, message);
|
||||
public boolean checkNotNull(Object actual, String message) {
|
||||
echo("Testing : " + message);
|
||||
if (Objects.isNull(actual)) {
|
||||
getLastTestCase().addAssert(new AssertionFailedException(
|
||||
message + " : Expected not null value"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertFalse(boolean actual, String message) {
|
||||
getLastTestCase().assertEquals(actual, false, message);
|
||||
public boolean checkFalse(boolean actual, String message) {
|
||||
return checkEquals(actual, false, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertTrue(boolean actual, String message) {
|
||||
getLastTestCase().assertEquals(actual, true, message);
|
||||
public boolean checkTrue(boolean actual, String message) {
|
||||
return checkEquals(actual, true, message);
|
||||
}
|
||||
|
||||
public void assertContains(Set<?> found, Set<?> expected, String message) {
|
||||
public boolean checkContains(Set<?> found, Set<?> expected, String message) {
|
||||
Set<?> copy = new HashSet<>(expected);
|
||||
copy.removeAll(found);
|
||||
assertTrue(found.containsAll(expected), message + " : " + copy);
|
||||
return checkTrue(found.containsAll(expected), message + " : " + copy);
|
||||
}
|
||||
|
||||
public void addFailure(Throwable th) {
|
||||
@ -99,10 +103,10 @@ public class TestResult extends TestBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@code TestFailedException} if one of the asserts are failed
|
||||
* Throws {@code TestFailedException} if one of the checks are failed
|
||||
* or an exception occurs. Prints error message of failed test cases.
|
||||
*
|
||||
* @throws TestFailedException if one of the asserts are failed
|
||||
* @throws TestFailedException if one of the checks are failed
|
||||
* or an exception occurs
|
||||
*/
|
||||
public void checkStatus() throws TestFailedException {
|
||||
@ -115,7 +119,7 @@ public class TestResult extends TestBase {
|
||||
private class Info {
|
||||
|
||||
private final String info;
|
||||
private final List<String> asserts;
|
||||
private final List<AssertionFailedException> asserts;
|
||||
private final List<Throwable> errors;
|
||||
|
||||
private Info(String info) {
|
||||
@ -137,45 +141,20 @@ public class TestResult extends TestBase {
|
||||
printf("[ERROR] : %s\n", getStackTrace(th));
|
||||
}
|
||||
|
||||
public void addFailure(String message) {
|
||||
String stackTrace = Stream.of(Thread.currentThread().getStackTrace())
|
||||
// just to get stack trace without TestResult and Thread
|
||||
.filter(e -> !"TestResult.java".equals(e.getFileName()) &&
|
||||
!"java.lang.Thread".equals(e.getClassName()))
|
||||
.map(e -> "\tat " + e)
|
||||
.collect(joining("\n"));
|
||||
asserts.add(format("%s\n%s", message, stackTrace));
|
||||
printf("[ASSERT] : %s\n", message);
|
||||
}
|
||||
|
||||
public void assertEquals(Object actual, Object expected, String message) {
|
||||
echo("Testing : " + message);
|
||||
if (!Objects.equals(actual, expected)) {
|
||||
addFailure(message + ": Got: " + actual + ", " + "Expected: " + expected);
|
||||
}
|
||||
}
|
||||
|
||||
public void assertNotNull(Object actual, String message) {
|
||||
echo("Testing : " + message);
|
||||
if (actual == null) {
|
||||
addFailure(message + " : Expected not null value");
|
||||
}
|
||||
public void addAssert(AssertionFailedException e) {
|
||||
asserts.add(e);
|
||||
printf("[ASSERT] : %s\n", getStackTrace(e));
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return (asserts.size() > 0 ? getAssertMessage() + "\n" : "") + getErrorMessage();
|
||||
return (asserts.size() > 0 ? getErrorMessage("[ASSERT]", asserts) + "\n" : "")
|
||||
+ getErrorMessage("[ERROR]", errors);
|
||||
}
|
||||
|
||||
public String getAssertMessage() {
|
||||
return asserts.stream()
|
||||
.map(failure -> "[ASSERT] : " + failure)
|
||||
.collect(joining("\n"));
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errors.stream()
|
||||
.map(throwable -> format("[ERROR] : %s", getStackTrace(throwable)))
|
||||
.collect(joining("\n"));
|
||||
public String getErrorMessage(String header, List<? extends Throwable> list) {
|
||||
return list.stream()
|
||||
.map(throwable -> String.format("%s : %s", header, getStackTrace(throwable)))
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public String getStackTrace(Throwable throwable) {
|
||||
|
23
langtools/test/tools/javac/conditional/8064464/T8064464.java
Normal file
23
langtools/test/tools/javac/conditional/8064464/T8064464.java
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8064464
|
||||
* @summary regression with type inference of conditional expression
|
||||
* @compile/fail/ref=T8064464.out -XDrawDiagnostics T8064464.java
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class T8064464 {
|
||||
|
||||
String f(Object o) { return null; }
|
||||
Integer f(int i) { return null; }
|
||||
|
||||
<X extends Integer> X id() { return null; }
|
||||
|
||||
void m(List<Integer> lx) {
|
||||
Integer i1 = f(!lx.isEmpty() ? 0 : lx.get(0)); //ok --> f(int)
|
||||
Integer i2 = f(!lx.isEmpty() ? lx.get(0) : 0); //ok --> f(int)
|
||||
f(!lx.isEmpty() ? id() : 0); // ambiguous
|
||||
f(!lx.isEmpty() ? 0 : id()); // ambiguous
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
T8064464.java:20:5: compiler.err.ref.ambiguous: f, kindname.method, f(java.lang.Object), T8064464, kindname.method, f(int), T8064464
|
||||
T8064464.java:21:5: compiler.err.ref.ambiguous: f, kindname.method, f(java.lang.Object), T8064464, kindname.method, f(int), T8064464
|
||||
2 errors
|
@ -24,9 +24,9 @@
|
||||
// key: compiler.err.neither.conditional.subtype
|
||||
|
||||
class NeitherConditionalSubtype {
|
||||
public int test(Object o) {
|
||||
public int test(boolean cond, Object o) {
|
||||
// Should fail to compile since Object.wait() has a void return type.
|
||||
System.out.println(o instanceof String ? o.hashCode() : o.wait());
|
||||
(o instanceof String ? o.hashCode() : o.wait()).toString();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
* @test
|
||||
* @bug 6499673
|
||||
* @library /tools/javac/lib
|
||||
* @ignore 8062245 Test executes incorrect class
|
||||
* @build JavacTestingAbstractProcessor BoundsTest
|
||||
* @run main BoundsTest
|
||||
* @summary Assertion check for TypeVariable.getUpperBound() fails
|
||||
@ -86,8 +85,8 @@ public class BoundsTest {
|
||||
};
|
||||
private static final String[] NoBounds_supers = {};
|
||||
|
||||
private HashSet<CharSequence> expected_bounds;
|
||||
private HashSet<CharSequence> expected_supers;
|
||||
private HashSet<String> expected_bounds;
|
||||
private HashSet<String> expected_supers;
|
||||
|
||||
private static final File classesdir = new File("intersectionproperties");
|
||||
private static final JavaCompiler comp =
|
||||
@ -99,8 +98,8 @@ public class BoundsTest {
|
||||
final String[] Test_bounds, final String[] Test_supers)
|
||||
throws IOException {
|
||||
System.err.println("Testing " + Test_name);
|
||||
expected_bounds = new HashSet<CharSequence>(Arrays.asList(Test_bounds));
|
||||
expected_supers = new HashSet<CharSequence>(Arrays.asList(Test_supers));
|
||||
expected_bounds = new HashSet<>(Arrays.asList(Test_bounds));
|
||||
expected_supers = new HashSet<>(Arrays.asList(Test_supers));
|
||||
final Iterable<? extends JavaFileObject> files =
|
||||
fm.getJavaFileObjectsFromFiles(Collections.singleton(writeFile(classesdir, Test_name, Test_contents)));
|
||||
final JavacTask ct =
|
||||
@ -130,7 +129,7 @@ public class BoundsTest {
|
||||
}
|
||||
|
||||
public static void main(String... args) throws IOException {
|
||||
new IntersectionPropertiesTest().run();
|
||||
new BoundsTest().run();
|
||||
}
|
||||
|
||||
private static File writeFile(File dir, String path, String body)
|
||||
@ -166,18 +165,17 @@ public class BoundsTest {
|
||||
final List<? extends TypeMirror> bounds = typeParameterElement.getBounds();
|
||||
final List<? extends TypeMirror> supers = processingEnv.getTypeUtils().directSupertypes(upperBound);
|
||||
|
||||
final HashSet<CharSequence> actual_bounds = new HashSet<CharSequence>();
|
||||
final HashSet<CharSequence> actual_supers = new HashSet<CharSequence>();
|
||||
final HashSet<String> actual_bounds = new HashSet<>();
|
||||
final HashSet<String> actual_supers = new HashSet<>();
|
||||
|
||||
for(TypeMirror ty : bounds) {
|
||||
actual_bounds.add(((TypeElement)((DeclaredType)ty).asElement()).getQualifiedName());
|
||||
actual_bounds.add(((TypeElement)((DeclaredType)ty).asElement()).getQualifiedName().toString());
|
||||
}
|
||||
|
||||
for(TypeMirror ty : supers) {
|
||||
actual_supers.add(((TypeElement)((DeclaredType)ty).asElement()).getQualifiedName());
|
||||
actual_supers.add(((TypeElement)((DeclaredType)ty).asElement()).getQualifiedName().toString());
|
||||
}
|
||||
|
||||
|
||||
if (!expected_bounds.equals(actual_bounds)) {
|
||||
System.err.println("Mismatched expected and actual bounds.");
|
||||
System.err.println("Expected:");
|
||||
@ -190,7 +188,7 @@ public class BoundsTest {
|
||||
}
|
||||
|
||||
if (!expected_supers.equals(actual_supers)) {
|
||||
System.err.println("Mismatched expected and actual bounds.");
|
||||
System.err.println("Mismatched expected and actual supers.");
|
||||
System.err.println("Expected:");
|
||||
for(CharSequence tm : expected_supers)
|
||||
System.err.println(" " + tm);
|
||||
|
217
langtools/test/tools/javac/scope/DupUnsharedTest.java
Normal file
217
langtools/test/tools/javac/scope/DupUnsharedTest.java
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary WriteableScope.dupUnshared not working properly for shared Scopes.
|
||||
*/
|
||||
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Scope.*;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.file.JavacFileManager;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class DupUnsharedTest {
|
||||
public static void main(String... args) throws Exception {
|
||||
new DupUnsharedTest().run();
|
||||
}
|
||||
|
||||
Context context;
|
||||
Names names;
|
||||
Symtab symtab;
|
||||
Name a;
|
||||
Name b;
|
||||
int errors;
|
||||
|
||||
public DupUnsharedTest() {
|
||||
context = new Context();
|
||||
JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab
|
||||
names = Names.instance(context);
|
||||
symtab = Symtab.instance(context);
|
||||
a = names.fromString("a");
|
||||
b = names.fromString("b");
|
||||
}
|
||||
|
||||
void run() throws Exception {
|
||||
runScopeContentTest();
|
||||
runClashTest();
|
||||
|
||||
if (errors > 0)
|
||||
throw new AssertionError("Errors detected (" + errors + ").");
|
||||
}
|
||||
|
||||
void runScopeContentTest() throws Exception {
|
||||
Set<Symbol> expected = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
Set<Symbol> notExpected = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
WriteableScope s1 = WriteableScope.create(symtab.rootPackage);
|
||||
ClassSymbol acceptSym = symtab.arrayClass;
|
||||
s1.enter(acceptSym);
|
||||
expected.add(acceptSym);
|
||||
WriteableScope s2 = s1.dup();
|
||||
fillScope(s2, notExpected, a);
|
||||
WriteableScope s3 = s2.dup();
|
||||
fillScope(s3, notExpected, b);
|
||||
WriteableScope s4 = s1.dupUnshared();
|
||||
assertEquals(toSet(s4.getSymbols()), expected);
|
||||
assertEquals(toSet(s4.getSymbolsByName(a)), Collections.emptySet());
|
||||
assertEquals(toSet(s4.getSymbolsByName(b)), Collections.emptySet());
|
||||
assertEquals(toSet(s4.getSymbolsByName(acceptSym.name)), expected);
|
||||
for (Symbol sym : notExpected) {
|
||||
try {
|
||||
s4.remove(sym);
|
||||
} catch (Exception ex) {
|
||||
System.err.println("s4.remove(" + sym + "); crashes with exception:");
|
||||
ex.printStackTrace();
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fillScope(WriteableScope scope, Set<Symbol> notExpected, Name name) {
|
||||
VarSymbol var1 = new VarSymbol(0, name, Type.noType, symtab.arrayClass);
|
||||
VarSymbol var2 = new VarSymbol(0, name, Type.noType, symtab.autoCloseableClose.owner);
|
||||
scope.enter(var1);
|
||||
scope.enter(var2);
|
||||
scope.remove(var1);
|
||||
notExpected.add(var1);
|
||||
notExpected.add(var2);
|
||||
}
|
||||
|
||||
Set<Symbol> toSet(Iterable<Symbol> it) {
|
||||
Set<Symbol> result = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
|
||||
for (Symbol sym : it) {
|
||||
result.add(sym);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void assertEquals(Set<Symbol> set1, Set<Symbol> set2) {
|
||||
if (!Objects.equals(set1, set2)) {
|
||||
System.err.println("Sets are not equals: s1=" + set1 + "; s2=" + set2);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests tests the following situation.
|
||||
* - consider empty Scope S1
|
||||
* - a Symbol with name 'A' is added into S1
|
||||
* - S1 is dupped into S2
|
||||
* - a Symbol with name 'B', clashing with 'A', is added into S2
|
||||
* - so the table now looks like: [..., A, ..., B, ...]
|
||||
* - S2 is doubled. As a consequence, the table is re-hashed, and looks like:
|
||||
* [..., B, ..., A, ...] (note that re-hashing goes from the end, hence the original order).
|
||||
* - B has been chosen so that it clashes in the doubled scope as well. So when looking up 'A',
|
||||
* B is found (and rejected) first, and only then the A's bucket is tested.
|
||||
* - S2 is dupUshared - the resulting table needs to look like: [..., /sentinel/, ..., A, ...], not
|
||||
* [..., null, ..., A, ...], as in the latter case lookups would see 'null' while looking for
|
||||
* 'A' and would stop the search prematurely.
|
||||
*/
|
||||
void runClashTest() throws Exception {
|
||||
WriteableScope emptyScope = WriteableScope.create(symtab.unnamedPackage);
|
||||
Field tableField = emptyScope.getClass().getDeclaredField("table");
|
||||
tableField.setAccessible(true);
|
||||
Method dble = emptyScope.getClass().getDeclaredMethod("dble");
|
||||
dble.setAccessible(true);
|
||||
Method getIndex = emptyScope.getClass().getDeclaredMethod("getIndex", Name.class);
|
||||
getIndex.setAccessible(true);
|
||||
|
||||
int tries = 0;
|
||||
|
||||
//find a name that will be in the first bucket in table (so that a conflicting name
|
||||
//will be in placed in a bucket after this one).
|
||||
Name first = names.fromString("a");
|
||||
while ((Integer) getIndex.invoke(emptyScope, first) != 0) {
|
||||
if (tries++ > MAX_TRIES) {
|
||||
System.err.println("could not find a name that would be placed in the first bucket");
|
||||
errors++;
|
||||
return ;
|
||||
}
|
||||
first = names.fromString("a" + first.toString());
|
||||
}
|
||||
|
||||
System.out.println("first name: " + first);
|
||||
|
||||
//now, find another name, that will clash with the first one both in the empty and a doubled scope:
|
||||
Scope doubledEmptyScope = WriteableScope.create(symtab.unnamedPackage);
|
||||
dble.invoke(doubledEmptyScope);
|
||||
Integer firstNameTestScopeIndex = (Integer) getIndex.invoke(emptyScope, first);
|
||||
Integer firstNameDoubleScopeIndex = (Integer) getIndex.invoke(doubledEmptyScope, first);
|
||||
Name other = names.fromString("b");
|
||||
while (!Objects.equals(firstNameTestScopeIndex, getIndex.invoke(emptyScope, other)) ||
|
||||
!Objects.equals(firstNameDoubleScopeIndex, getIndex.invoke(doubledEmptyScope, other))) {
|
||||
if (tries++ > MAX_TRIES) {
|
||||
System.err.println("could not find a name that would properly clash with the first chosen name");
|
||||
errors++;
|
||||
return ;
|
||||
}
|
||||
other = names.fromString("b" + other);
|
||||
}
|
||||
|
||||
System.out.println("other name: " + other);
|
||||
|
||||
Symbol firstSymbol = new VarSymbol(0, first, Type.noType, null);
|
||||
Symbol otherSymbol = new VarSymbol(0, other, Type.noType, null);
|
||||
|
||||
//test the situation described above:
|
||||
WriteableScope testScope1 = WriteableScope.create(symtab.unnamedPackage);
|
||||
testScope1.enter(firstSymbol);
|
||||
|
||||
WriteableScope dupped1 = testScope1.dup();
|
||||
|
||||
dupped1.enter(otherSymbol);
|
||||
dble.invoke(dupped1);
|
||||
|
||||
if (testScope1.dupUnshared().findFirst(first) != firstSymbol) {
|
||||
System.err.println("cannot find the Symbol in the dupUnshared scope (1)");
|
||||
errors++;
|
||||
}
|
||||
|
||||
//also check a situation where the clashing Symbol is removed from the dupped scope:
|
||||
WriteableScope testScope2 = WriteableScope.create(symtab.unnamedPackage);
|
||||
testScope2.enter(firstSymbol);
|
||||
|
||||
WriteableScope dupped2 = testScope2.dup();
|
||||
|
||||
dupped2.enter(otherSymbol);
|
||||
dble.invoke(dupped2);
|
||||
dupped2.remove(otherSymbol);
|
||||
|
||||
if (testScope2.dupUnshared().findFirst(first) != firstSymbol) {
|
||||
System.err.println("cannot find the Symbol in the dupUnshared scope (2)");
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
int MAX_TRIES = 100; // max tries to find a hash clash before giving up.
|
||||
|
||||
}
|
46
langtools/test/tools/javac/util/NewlineOnlyDiagnostic.java
Normal file
46
langtools/test/tools/javac/util/NewlineOnlyDiagnostic.java
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import java.util.Set;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8060448
|
||||
* @summary Test that javac doesn't throw ArrayIndexOutOfBoundsException
|
||||
* when logging the message "\n"
|
||||
* @library /tools/javac/lib
|
||||
* @build JavacTestingAbstractProcessor NewlineOnlyDiagnostic
|
||||
* @compile -processor NewlineOnlyDiagnostic NewlineOnlyDiagnostic.java
|
||||
*/
|
||||
|
||||
public class NewlineOnlyDiagnostic extends JavacTestingAbstractProcessor {
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> types,RoundEnvironment rEnv) {
|
||||
processingEnv.getMessager().printMessage(Kind.NOTE,"\n");
|
||||
return true;
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@ -28,6 +29,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.FilterWriter;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@ -49,12 +51,15 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
@ -64,18 +69,20 @@ import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.ForwardingJavaFileManager;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.JavaFileObject.Kind;
|
||||
import javax.tools.JavaFileManager.Location;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.api.JavacTool;
|
||||
import java.io.IOError;
|
||||
|
||||
/**
|
||||
* Utility methods and classes for writing jtreg tests for
|
||||
@ -233,7 +240,7 @@ public class ToolBox {
|
||||
public void createDirectories(String... paths) throws IOException {
|
||||
if (paths.length == 0)
|
||||
throw new IllegalArgumentException("no directories specified");
|
||||
for (String p: paths)
|
||||
for (String p : paths)
|
||||
Files.createDirectories(Paths.get(p));
|
||||
}
|
||||
|
||||
@ -248,7 +255,7 @@ public class ToolBox {
|
||||
public void createDirectories(Path... paths) throws IOException {
|
||||
if (paths.length == 0)
|
||||
throw new IllegalArgumentException("no directories specified");
|
||||
for (Path p: paths)
|
||||
for (Path p : paths)
|
||||
Files.createDirectories(p);
|
||||
}
|
||||
|
||||
@ -262,7 +269,7 @@ public class ToolBox {
|
||||
public void deleteFiles(String... files) throws IOException {
|
||||
if (files.length == 0)
|
||||
throw new IllegalArgumentException("no files specified");
|
||||
for (String file: files)
|
||||
for (String file : files)
|
||||
Files.delete(Paths.get(file));
|
||||
}
|
||||
|
||||
@ -392,7 +399,7 @@ public class ToolBox {
|
||||
public void writeJavaFiles(Path dir, String... contents) throws IOException {
|
||||
if (contents.length == 0)
|
||||
throw new IllegalArgumentException("no content specified for any files");
|
||||
for (String c: contents) {
|
||||
for (String c : contents) {
|
||||
new JavaSource(c).write(dir);
|
||||
}
|
||||
}
|
||||
@ -1090,7 +1097,7 @@ public class ToolBox {
|
||||
|
||||
private List<File> toFiles(String path) {
|
||||
List<File> result = new ArrayList<>();
|
||||
for (String s: path.split(File.pathSeparator)) {
|
||||
for (String s : path.split(File.pathSeparator)) {
|
||||
if (!s.isEmpty())
|
||||
result.add(new File(s));
|
||||
}
|
||||
@ -1108,7 +1115,7 @@ public class ToolBox {
|
||||
if (fileObjects == null)
|
||||
return filesAsFileObjects;
|
||||
List<JavaFileObject> combinedList = new ArrayList<>();
|
||||
for (JavaFileObject o: filesAsFileObjects)
|
||||
for (JavaFileObject o : filesAsFileObjects)
|
||||
combinedList.add(o);
|
||||
combinedList.addAll(fileObjects);
|
||||
return combinedList;
|
||||
@ -1308,6 +1315,7 @@ public class ToolBox {
|
||||
private String mainClass;
|
||||
private Path baseDir;
|
||||
private List<Path> paths;
|
||||
private Set<FileObject> fileObjects;
|
||||
|
||||
/**
|
||||
* Creates a task to write jar files, using API mode.
|
||||
@ -1315,6 +1323,7 @@ public class ToolBox {
|
||||
public JarTask() {
|
||||
super(Mode.API);
|
||||
paths = Collections.emptyList();
|
||||
fileObjects = new LinkedHashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1391,6 +1400,53 @@ public class ToolBox {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a set of file objects to be written into the jar file, by copying them
|
||||
* from a Location in a JavaFileManager.
|
||||
* The file objects to be written are specified by a series of paths;
|
||||
* each path can be in one of the following forms:
|
||||
* <ul>
|
||||
* <li>The name of a class. For example, java.lang.Object.
|
||||
* In this case, the corresponding .class file will be written to the jar file.
|
||||
* <li>the name of a package followed by {@code .*}. For example, {@code java.lang.*}.
|
||||
* In this case, all the class files in the specified package will be written to
|
||||
* the jar file.
|
||||
* <li>the name of a package followed by {@code .**}. For example, {@code java.lang.**}.
|
||||
* In this case, all the class files in the specified package, and any subpackages
|
||||
* will be written to the jar file.
|
||||
* </ul>
|
||||
*
|
||||
* @param fm the file manager in which to find the file objects
|
||||
* @param l the location in which to find the file objects
|
||||
* @param paths the paths specifying the file objects to be copied
|
||||
* @return this task object
|
||||
* @throws IOException if errors occur while determining the set of file objects
|
||||
*/
|
||||
public JarTask files(JavaFileManager fm, Location l, String... paths)
|
||||
throws IOException {
|
||||
for (String p : paths) {
|
||||
if (p.endsWith(".**"))
|
||||
addPackage(fm, l, p.substring(0, p.length() - 3), true);
|
||||
else if (p.endsWith(".*"))
|
||||
addPackage(fm, l, p.substring(0, p.length() - 2), false);
|
||||
else
|
||||
addFile(fm, l, p);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addPackage(JavaFileManager fm, Location l, String pkg, boolean recurse)
|
||||
throws IOException {
|
||||
for (JavaFileObject fo : fm.list(l, pkg, EnumSet.allOf(JavaFileObject.Kind.class), recurse)) {
|
||||
fileObjects.add(fo);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFile(JavaFileManager fm, Location l, String path) throws IOException {
|
||||
JavaFileObject fo = fm.getJavaFileForInput(l, path, Kind.CLASS);
|
||||
fileObjects.add(fo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides limited jar command-like functionality.
|
||||
* The supported commands are:
|
||||
@ -1464,42 +1520,19 @@ public class ToolBox {
|
||||
StreamOutput sysOut = new StreamOutput(System.out, System::setOut);
|
||||
StreamOutput sysErr = new StreamOutput(System.err, System::setErr);
|
||||
|
||||
int rc;
|
||||
Map<OutputKind, String> outputMap = new HashMap<>();
|
||||
|
||||
try (OutputStream os = Files.newOutputStream(jar);
|
||||
JarOutputStream jos = openJar(os, m)) {
|
||||
Path base = (baseDir == null) ? currDir : baseDir;
|
||||
for (Path path: paths) {
|
||||
Files.walkFileTree(base.resolve(path), new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
try {
|
||||
String p = base.relativize(file)
|
||||
.normalize()
|
||||
.toString()
|
||||
.replace(File.separatorChar, '/');
|
||||
JarEntry e = new JarEntry(p);
|
||||
jos.putNextEntry(e);
|
||||
jos.write(Files.readAllBytes(file));
|
||||
jos.closeEntry();
|
||||
return FileVisitResult.CONTINUE;
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error adding " + file + " to jar file: " + e);
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
rc = 0;
|
||||
writeFiles(jos);
|
||||
writeFileObjects(jos);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error opening " + jar + ": " + e);
|
||||
rc = 1;
|
||||
error("Exception while opening " + jar, e);
|
||||
} finally {
|
||||
outputMap.put(OutputKind.STDOUT, sysOut.close());
|
||||
outputMap.put(OutputKind.STDERR, sysErr.close());
|
||||
}
|
||||
return checkExit(new Result(this, rc, outputMap));
|
||||
return checkExit(new Result(this, (errors == 0) ? 0 : 1, outputMap));
|
||||
}
|
||||
|
||||
private JarOutputStream openJar(OutputStream os, Manifest m) throws IOException {
|
||||
@ -1512,6 +1545,79 @@ public class ToolBox {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeFiles(JarOutputStream jos) throws IOException {
|
||||
Path base = (baseDir == null) ? currDir : baseDir;
|
||||
for (Path path : paths) {
|
||||
Files.walkFileTree(base.resolve(path), new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
try {
|
||||
String p = base.relativize(file)
|
||||
.normalize()
|
||||
.toString()
|
||||
.replace(File.separatorChar, '/');
|
||||
JarEntry e = new JarEntry(p);
|
||||
jos.putNextEntry(e);
|
||||
try {
|
||||
jos.write(Files.readAllBytes(file));
|
||||
} finally {
|
||||
jos.closeEntry();
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
} catch (IOException e) {
|
||||
error("Exception while adding " + file + " to jar file", e);
|
||||
return FileVisitResult.TERMINATE;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void writeFileObjects(JarOutputStream jos) throws IOException {
|
||||
for (FileObject fo : fileObjects) {
|
||||
String p = guessPath(fo);
|
||||
JarEntry e = new JarEntry(p);
|
||||
jos.putNextEntry(e);
|
||||
try {
|
||||
byte[] buf = new byte[1024];
|
||||
try (BufferedInputStream in = new BufferedInputStream(fo.openInputStream())) {
|
||||
int n;
|
||||
while ((n = in.read(buf)) > 0)
|
||||
jos.write(buf, 0, n);
|
||||
} catch (IOException ex) {
|
||||
error("Exception while adding " + fo.getName() + " to jar file", ex);
|
||||
}
|
||||
} finally {
|
||||
jos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A jar: URL is of the form jar:URL!/entry where URL is a URL for the .jar file itself.
|
||||
* In Symbol files (i.e. ct.sym) the underlying entry is prefixed META-INF/sym/<base>.
|
||||
*/
|
||||
private final Pattern jarEntry = Pattern.compile(".*!/(?:META-INF/sym/[^/]+/)?(.*)");
|
||||
|
||||
private String guessPath(FileObject fo) {
|
||||
URI u = fo.toUri();
|
||||
switch (u.getScheme()) {
|
||||
case "jar":
|
||||
Matcher m = jarEntry.matcher(u.getSchemeSpecificPart());
|
||||
if (m.matches()) {
|
||||
return m.group(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
throw new IllegalArgumentException(fo.getName());
|
||||
}
|
||||
|
||||
private void error(String message, Throwable t) {
|
||||
out.println("Error: " + message + ": " + t);
|
||||
errors++;
|
||||
}
|
||||
|
||||
private int errors;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user