summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bincompat-backward.whitelist.conf4
-rw-r--r--bincompat-forward.whitelist.conf8
-rw-r--r--build-ant-macros.xml2
-rw-r--r--build.number2
-rwxr-xr-xbuild.xml2
-rw-r--r--spec/03-types.md3
-rw-r--r--src/asm/README30
-rw-r--r--src/asm/scala/tools/asm/AnnotationVisitor.java8
-rw-r--r--src/asm/scala/tools/asm/AnnotationWriter.java55
-rw-r--r--src/asm/scala/tools/asm/ByteVector.java99
-rw-r--r--src/asm/scala/tools/asm/ClassReader.java366
-rw-r--r--src/asm/scala/tools/asm/ClassVisitor.java46
-rw-r--r--src/asm/scala/tools/asm/ClassWriter.java124
-rw-r--r--src/asm/scala/tools/asm/Context.java35
-rw-r--r--src/asm/scala/tools/asm/CustomAttr.java2
-rw-r--r--src/asm/scala/tools/asm/FieldVisitor.java41
-rw-r--r--src/asm/scala/tools/asm/FieldWriter.java58
-rw-r--r--src/asm/scala/tools/asm/Frame.java23
-rw-r--r--src/asm/scala/tools/asm/Handle.java13
-rw-r--r--src/asm/scala/tools/asm/Item.java3
-rw-r--r--src/asm/scala/tools/asm/MethodVisitor.java254
-rw-r--r--src/asm/scala/tools/asm/MethodWriter.java338
-rw-r--r--src/asm/scala/tools/asm/Opcodes.java7
-rw-r--r--src/asm/scala/tools/asm/Type.java11
-rw-r--r--src/asm/scala/tools/asm/TypePath.java193
-rw-r--r--src/asm/scala/tools/asm/TypeReference.java452
-rw-r--r--src/asm/scala/tools/asm/signature/SignatureVisitor.java7
-rw-r--r--src/asm/scala/tools/asm/signature/SignatureWriter.java2
-rw-r--r--src/asm/scala/tools/asm/tree/AbstractInsnNode.java78
-rw-r--r--src/asm/scala/tools/asm/tree/AnnotationNode.java14
-rw-r--r--src/asm/scala/tools/asm/tree/ClassNode.java80
-rw-r--r--src/asm/scala/tools/asm/tree/FieldInsnNode.java8
-rw-r--r--src/asm/scala/tools/asm/tree/FieldNode.java76
-rw-r--r--src/asm/scala/tools/asm/tree/IincInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/InsnList.java20
-rw-r--r--src/asm/scala/tools/asm/tree/InsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/IntInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java4
-rw-r--r--src/asm/scala/tools/asm/tree/JumpInsnNode.java4
-rw-r--r--src/asm/scala/tools/asm/tree/LdcInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java157
-rw-r--r--src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/MethodInsnNode.java35
-rw-r--r--src/asm/scala/tools/asm/tree/MethodNode.java260
-rw-r--r--src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/ParameterNode.java76
-rw-r--r--src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/TryCatchBlockNode.java59
-rw-r--r--src/asm/scala/tools/asm/tree/TypeAnnotationNode.java100
-rw-r--r--src/asm/scala/tools/asm/tree/TypeInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/VarInsnNode.java3
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java1
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java2
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java2
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/Frame.java9
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java2
-rw-r--r--src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java2
-rw-r--r--src/asm/scala/tools/asm/util/ASMifier.java141
-rw-r--r--src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java4
-rw-r--r--src/asm/scala/tools/asm/util/CheckClassAdapter.java119
-rw-r--r--src/asm/scala/tools/asm/util/CheckFieldAdapter.java26
-rw-r--r--src/asm/scala/tools/asm/util/CheckMethodAdapter.java159
-rw-r--r--src/asm/scala/tools/asm/util/CheckSignatureAdapter.java4
-rw-r--r--src/asm/scala/tools/asm/util/Printer.java95
-rw-r--r--src/asm/scala/tools/asm/util/Textifier.java279
-rw-r--r--src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java2
-rw-r--r--src/asm/scala/tools/asm/util/TraceClassVisitor.java13
-rw-r--r--src/asm/scala/tools/asm/util/TraceFieldVisitor.java13
-rw-r--r--src/asm/scala/tools/asm/util/TraceMethodVisitor.java77
-rw-r--r--src/asm/scala/tools/asm/util/TraceSignatureVisitor.java4
-rw-r--r--src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala10
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala30
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/Platform.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala28
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala53
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala20
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala23
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeICodeCommon.scala25
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala18
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala21
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala11
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala9
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala25
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala10
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/Delambdafy.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala86
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/Solving.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala25
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala15
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala9
-rw-r--r--src/eclipse/partest/.classpath6
-rw-r--r--src/library/scala/StringContext.scala97
-rw-r--r--src/library/scala/collection/LinearSeq.scala2
-rw-r--r--src/library/scala/collection/TraversableLike.scala8
-rw-r--r--src/library/scala/collection/TraversableOnce.scala7
-rw-r--r--src/library/scala/collection/convert/Wrappers.scala2
-rw-r--r--src/library/scala/reflect/Manifest.scala3
-rw-r--r--src/partest-extras/scala/tools/partest/BytecodeTest.scala2
-rw-r--r--src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java2
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala24
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala5
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala11
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala3
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css1
-rw-r--r--test/files/jvm/beanInfo.check6
-rw-r--r--test/files/jvm/beanInfo/C_1.scala9
-rw-r--r--test/files/jvm/beanInfo/Test_2.scala17
-rw-r--r--test/files/jvm/t8582.check44
-rw-r--r--test/files/jvm/t8582.scala81
-rw-r--r--test/files/jvm/unreachable.flags1
-rw-r--r--test/files/neg/double-def-top-level.check7
-rw-r--r--test/files/neg/double-def-top-level/A_1.scala4
-rw-r--r--test/files/neg/double-def-top-level/B_2.scala2
-rw-r--r--test/files/neg/double-def-top-level/C_3.scala2
-rw-r--r--test/files/neg/double-def-top-level/D_3.scala2
-rw-r--r--test/files/neg/t6162-inheritance.check8
-rw-r--r--test/files/neg/t6771b.check2
-rw-r--r--test/files/neg/t6771b.scala2
-rw-r--r--test/files/neg/t6988.check7
-rw-r--r--test/files/neg/t6988.scala10
-rw-r--r--test/files/neg/t8325-b.check10
-rw-r--r--test/files/neg/t8325-b.scala4
-rw-r--r--test/files/neg/t8325-c.check7
-rw-r--r--test/files/neg/t8325-c.scala4
-rw-r--r--test/files/neg/t8325.check15
-rw-r--r--test/files/neg/t8325.scala11
-rw-r--r--test/files/pos/dotless-targs.flags1
-rw-r--r--test/files/pos/t8157-2.10.flags1
-rw-r--r--test/files/pos/t8157-2.10.scala5
-rw-r--r--test/files/pos/t8325.scala9
-rw-r--r--test/files/pos/t8523.flags1
-rw-r--r--test/files/pos/t8523.scala10
-rw-r--r--test/files/pos/t8531/MyEnum.java5
-rw-r--r--test/files/pos/t8531/Test.scala24
-rw-r--r--test/files/pos/t8546.flags1
-rw-r--r--test/files/pos/t8546.scala49
-rw-r--r--test/files/pos/t8578.flags1
-rw-r--r--test/files/pos/t8578.scala18
-rw-r--r--test/files/pos/t8617.flags1
-rw-r--r--test/files/pos/t8617.scala10
-rw-r--r--test/files/pos/t8625.scala5
-rw-r--r--test/files/run/applydynamic_sip.flags1
-rw-r--r--test/files/run/classfile-format-51.scala14
-rw-r--r--test/files/run/interop_typetags_are_manifests.flags1
-rw-r--r--test/files/run/large_class.check3
-rw-r--r--test/files/run/large_class.scala27
-rw-r--r--test/files/run/macro-openmacros.flags3
-rw-r--r--test/files/run/macro-parse-position.flags1
-rw-r--r--test/files/run/macroPlugins-macroExpand.flags1
-rw-r--r--test/files/run/macroPlugins-typedMacroBody.flags1
-rw-r--r--test/files/run/t3569.scala3
-rw-r--r--test/files/run/t5256h.scala3
-rw-r--r--test/files/run/t5905-features.flags1
-rw-r--r--test/files/run/t5905-features.scala29
-rw-r--r--test/files/run/t5905b-features.check1
-rw-r--r--test/files/run/t5905b-features.scala15
-rw-r--r--test/files/run/t6327.flags1
-rw-r--r--test/files/run/t6663.flags1
-rw-r--r--test/files/run/t6731.flags1
-rw-r--r--test/files/run/t6988.check2
-rw-r--r--test/files/run/t6988.scala9
-rw-r--r--test/files/run/t7852.scala2
-rw-r--r--test/files/run/t7974.flags1
-rw-r--r--test/files/run/t7974/Test.scala2
-rw-r--r--test/files/run/t8196.check7
-rw-r--r--test/files/run/t8196.scala51
-rw-r--r--test/files/run/t8442.check1
-rw-r--r--test/files/run/t8442/A_1.java4
-rw-r--r--test/files/run/t8442/B_1.java3
-rw-r--r--test/files/run/t8442/C_2.scala5
-rw-r--r--test/files/run/t8442/Test.scala29
-rw-r--r--test/files/run/t8549.check1
-rw-r--r--test/files/run/t8549.scala186
-rw-r--r--test/files/run/t8549b.scala16
-rw-r--r--test/files/run/t8570.flags1
-rw-r--r--test/files/run/t8570.scala10
-rw-r--r--test/files/run/t8570a.check1
-rw-r--r--test/files/run/t8570a.flags1
-rw-r--r--test/files/run/t8570a.scala14
-rw-r--r--test/files/run/t8574.scala27
-rw-r--r--test/files/run/t8601-closure-elim.flags1
-rw-r--r--test/files/run/t8601-closure-elim.scala26
-rw-r--r--test/files/run/t8601.flags1
-rw-r--r--test/files/run/t8601.scala15
-rw-r--r--test/files/run/t8601b.flags1
-rw-r--r--test/files/run/t8601b.scala14
-rw-r--r--test/files/run/t8601c.flags1
-rw-r--r--test/files/run/t8601c.scala12
-rw-r--r--test/files/run/t8601d.flags1
-rw-r--r--test/files/run/t8601d.scala8
-rw-r--r--test/files/run/t8601e.flags1
-rw-r--r--test/files/run/t8601e/StaticInit.classbin0 -> 417 bytes
-rw-r--r--test/files/run/t8601e/StaticInit.java8
-rw-r--r--test/files/run/t8601e/Test.scala12
-rw-r--r--test/files/run/virtpatmat_staging.flags1
-rw-r--r--test/junit/scala/StringContextTest.scala51
-rw-r--r--test/junit/scala/collection/convert/MapWrapperTest.scala10
-rw-r--r--test/junit/scala/reflect/internal/ScopeTest.scala54
-rw-r--r--test/scaladoc/run/SI-8479.check1
-rwxr-xr-xtest/scaladoc/run/SI-8479.scala32
-rw-r--r--versions.properties14
217 files changed, 5391 insertions, 564 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf
index 703c5add42..ffacbf0442 100644
--- a/bincompat-backward.whitelist.conf
+++ b/bincompat-backward.whitelist.conf
@@ -181,6 +181,10 @@ filter {
{
matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticExistentialType"
problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf
index 5e869e3215..3cd985aeae 100644
--- a/bincompat-forward.whitelist.conf
+++ b/bincompat-forward.whitelist.conf
@@ -226,6 +226,14 @@ filter {
{
matchName="scala.reflect.api.Internals$ReificationSupportApi$SyntacticTypeProjectionExtractor"
problemName=MissingClassProblem
+ },
+ {
+ matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$followStatic"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/build-ant-macros.xml b/build-ant-macros.xml
index ea5652770e..bd0e723b9b 100644
--- a/build-ant-macros.xml
+++ b/build-ant-macros.xml
@@ -745,7 +745,7 @@
<attribute name="dir" default="${partest.dir}"/>
<attribute name="srcdir" default="files"/> <!-- TODO: make targets for `pending` and other subdirs -->
<attribute name="colors" default="${partest.colors}"/>
- <attribute name="scalacOpts" default="${scalac.args.optimise}"/>
+ <attribute name="scalacOpts" default="${partest.scalac_opts} ${scalac.args.optimise}"/>
<attribute name="pcp" default="${toString:partest.compilation.path}"/>
<attribute name="kinds"/>
<sequential>
diff --git a/build.number b/build.number
index 63a55339b9..4a0898529e 100644
--- a/build.number
+++ b/build.number
@@ -1,7 +1,7 @@
#Tue Sep 11 19:21:09 CEST 2007
version.major=2
version.minor=11
-version.patch=1
+version.patch=2
# This is the -N part of a version. if it's 0, it's dropped from maven versions.
version.bnum=0
diff --git a/build.xml b/build.xml
index a66c138cbe..ed12eb06d2 100755
--- a/build.xml
+++ b/build.xml
@@ -1505,7 +1505,7 @@ TODO:
BINARY COMPATIBILITY TESTING
============================================================================ -->
<target name="bc.init" depends="init" unless="maven-deps-done-mima">
- <property name="bc-reference-version" value="2.11.0-RC1"/>
+ <property name="bc-reference-version" value="2.11.0"/>
<property name="bc-build.dir" value="${build.dir}/bc"/>
<!-- Obtain mima -->
diff --git a/spec/03-types.md b/spec/03-types.md
index 66ddee8b7e..4a02c7a8c1 100644
--- a/spec/03-types.md
+++ b/spec/03-types.md
@@ -352,8 +352,7 @@ An infix type $T_1$ `op` $T_2$ consists of an infix
operator `op` which gets applied to two type operands $T_1$ and
$T_2$. The type is equivalent to the type application
`op`$[T_1, T_2]$. The infix operator `op` may be an
-arbitrary identifier, except for `*`, which is reserved as a postfix modifier
-denoting a [repeated parameter type](04-basic-declarations-and-definitions.html#repeated-parameters).
+arbitrary identifier.
All type infix operators have the same precedence; parentheses have to
be used for grouping. The [associativity](06-expressions.html#prefix-infix-and-postfix-operations)
diff --git a/src/asm/README b/src/asm/README
new file mode 100644
index 0000000000..3ceac88098
--- /dev/null
+++ b/src/asm/README
@@ -0,0 +1,30 @@
+Version 5.0.2, SVN r1741, tags/ASM_5_0_2
+
+Git SVN repo: https://github.com/lrytz/asm
+ - git svn howto: https://github.com/lrytz/asm/issues/1
+
+Upgrading ASM
+-------------
+
+Start by deleting all source files in src/asm/ and copy the ones from the latest ASM release.
+
+Excluded Files (don't copy):
+ - package.html files
+ - org/objectweb/asm/commons
+ - org/objectweb/asm/optimizer
+ - org/objectweb/asm/xml
+
+Re-packaging and cosmetic changes:
+ - convert line endings (there are some CRLF)
+ find src/asm/scala/tools/asm -name '*.java' | xargs dos2unix
+ - change package clauses
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/package org\.objectweb\.asm/package scala.tools.asm/'
+ - update imports
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/import org\.objectweb\.asm/import scala.tools.asm/'
+ - update @links, @associates
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/@link org\.objectweb\.asm/@link scala.tools.asm/'
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/@associates org\.objectweb\.asm/@associates scala.tools.asm/'
+ - remove trailing whitespace
+ find src/asm/scala/tools/asm -name '*.java' | xargs sed -i '' -e 's/[ ]*$//'
+
+Actual changes: check the git log for [asm-cherry-pick] after the previous upgrade.
diff --git a/src/asm/scala/tools/asm/AnnotationVisitor.java b/src/asm/scala/tools/asm/AnnotationVisitor.java
index c806ca71e8..abcaf1d6d1 100644
--- a/src/asm/scala/tools/asm/AnnotationVisitor.java
+++ b/src/asm/scala/tools/asm/AnnotationVisitor.java
@@ -41,7 +41,7 @@ public abstract class AnnotationVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -56,7 +56,7 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public AnnotationVisitor(final int api) {
this(api, null);
@@ -67,13 +67,13 @@ public abstract class AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param av
* the annotation visitor to which this visitor must delegate
* method calls. May be null.
*/
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
diff --git a/src/asm/scala/tools/asm/AnnotationWriter.java b/src/asm/scala/tools/asm/AnnotationWriter.java
index 8eb5b2ef48..6de74ce041 100644
--- a/src/asm/scala/tools/asm/AnnotationWriter.java
+++ b/src/asm/scala/tools/asm/AnnotationWriter.java
@@ -104,7 +104,7 @@ final class AnnotationWriter extends AnnotationVisitor {
*/
AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
this.cw = cw;
this.named = named;
this.bv = bv;
@@ -315,4 +315,57 @@ final class AnnotationWriter extends AnnotationVisitor {
}
}
}
+
+ /**
+ * Puts the given type reference and type path into the given bytevector.
+ * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param out
+ * where the type reference and type path must be put.
+ */
+ static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
+ switch (typeRef >>> 24) {
+ case 0x00: // CLASS_TYPE_PARAMETER
+ case 0x01: // METHOD_TYPE_PARAMETER
+ case 0x16: // METHOD_FORMAL_PARAMETER
+ out.putShort(typeRef >>> 16);
+ break;
+ case 0x13: // FIELD
+ case 0x14: // METHOD_RETURN
+ case 0x15: // METHOD_RECEIVER
+ out.putByte(typeRef >>> 24);
+ break;
+ case 0x47: // CAST
+ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
+ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
+ out.putInt(typeRef);
+ break;
+ // case 0x10: // CLASS_EXTENDS
+ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
+ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
+ // case 0x17: // THROWS
+ // case 0x42: // EXCEPTION_PARAMETER
+ // case 0x43: // INSTANCEOF
+ // case 0x44: // NEW
+ // case 0x45: // CONSTRUCTOR_REFERENCE
+ // case 0x46: // METHOD_REFERENCE
+ default:
+ out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
+ break;
+ }
+ if (typePath == null) {
+ out.putByte(0);
+ } else {
+ int length = typePath.b[typePath.offset] * 2 + 1;
+ out.putByteArray(typePath.b, typePath.offset, length);
+ }
+ }
}
diff --git a/src/asm/scala/tools/asm/ByteVector.java b/src/asm/scala/tools/asm/ByteVector.java
index 2bc63eb384..3bca7af12a 100644
--- a/src/asm/scala/tools/asm/ByteVector.java
+++ b/src/asm/scala/tools/asm/ByteVector.java
@@ -204,11 +204,14 @@ public class ByteVector {
* automatically enlarged if necessary.
*
* @param s
- * a String.
+ * a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector.
*/
public ByteVector putUTF8(final String s) {
int charLength = s.length();
+ if (charLength > 65535) {
+ throw new IllegalArgumentException();
+ }
int len = length;
if (len + 2 + charLength > data.length) {
enlarge(2 + charLength);
@@ -227,38 +230,68 @@ public class ByteVector {
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
} else {
- int byteLength = i;
- for (int j = i; j < charLength; ++j) {
- c = s.charAt(j);
- if (c >= '\001' && c <= '\177') {
- byteLength++;
- } else if (c > '\u07FF') {
- byteLength += 3;
- } else {
- byteLength += 2;
- }
- }
- data[length] = (byte) (byteLength >>> 8);
- data[length + 1] = (byte) byteLength;
- if (length + 2 + byteLength > data.length) {
- length = len;
- enlarge(2 + byteLength);
- data = this.data;
- }
- for (int j = i; j < charLength; ++j) {
- c = s.charAt(j);
- if (c >= '\001' && c <= '\177') {
- data[len++] = (byte) c;
- } else if (c > '\u07FF') {
- data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
- data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
- data[len++] = (byte) (0x80 | c & 0x3F);
- } else {
- data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
- data[len++] = (byte) (0x80 | c & 0x3F);
- }
- }
- break;
+ length = len;
+ return encodeUTF8(s, i, 65535);
+ }
+ }
+ length = len;
+ return this;
+ }
+
+ /**
+ * Puts an UTF8 string into this byte vector. The byte vector is
+ * automatically enlarged if necessary. The string length is encoded in two
+ * bytes before the encoded characters, if there is space for that (i.e. if
+ * this.length - i - 2 >= 0).
+ *
+ * @param s
+ * the String to encode.
+ * @param i
+ * the index of the first character to encode. The previous
+ * characters are supposed to have already been encoded, using
+ * only one byte per character.
+ * @param maxByteLength
+ * the maximum byte length of the encoded string, including the
+ * already encoded characters.
+ * @return this byte vector.
+ */
+ ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
+ int charLength = s.length();
+ int byteLength = i;
+ char c;
+ for (int j = i; j < charLength; ++j) {
+ c = s.charAt(j);
+ if (c >= '\001' && c <= '\177') {
+ byteLength++;
+ } else if (c > '\u07FF') {
+ byteLength += 3;
+ } else {
+ byteLength += 2;
+ }
+ }
+ if (byteLength > maxByteLength) {
+ throw new IllegalArgumentException();
+ }
+ int start = length - i - 2;
+ if (start >= 0) {
+ data[start] = (byte) (byteLength >>> 8);
+ data[start + 1] = (byte) byteLength;
+ }
+ if (length + byteLength - i > data.length) {
+ enlarge(byteLength - i);
+ }
+ int len = length;
+ for (int j = i; j < charLength; ++j) {
+ c = s.charAt(j);
+ if (c >= '\001' && c <= '\177') {
+ data[len++] = (byte) c;
+ } else if (c > '\u07FF') {
+ data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
+ data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
+ data[len++] = (byte) (0x80 | c & 0x3F);
+ } else {
+ data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
+ data[len++] = (byte) (0x80 | c & 0x3F);
}
}
length = len;
diff --git a/src/asm/scala/tools/asm/ClassReader.java b/src/asm/scala/tools/asm/ClassReader.java
index cc655c1b62..8b0e12cb04 100644
--- a/src/asm/scala/tools/asm/ClassReader.java
+++ b/src/asm/scala/tools/asm/ClassReader.java
@@ -166,7 +166,7 @@ public class ClassReader {
public ClassReader(final byte[] b, final int off, final int len) {
this.b = b;
// checks the class version
- if (readShort(off + 6) > Opcodes.V1_7) {
+ if (readShort(off + 6) > Opcodes.V1_8) {
throw new IllegalArgumentException();
}
// parses the constant pool
@@ -557,6 +557,8 @@ public class ClassReader {
String enclosingDesc = null;
int anns = 0;
int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
int innerClasses = 0;
Attribute attributes = null;
@@ -581,6 +583,9 @@ public class ClassReader {
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
} else if ("Deprecated".equals(attrName)) {
access |= Opcodes.ACC_DEPRECATED;
} else if ("Synthetic".equals(attrName)) {
@@ -592,6 +597,9 @@ public class ClassReader {
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
} else if ("BootstrapMethods".equals(attrName)) {
int[] bootstrapMethods = new int[readUnsignedShort(u + 8)];
for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) {
@@ -626,7 +634,7 @@ public class ClassReader {
enclosingDesc);
}
- // visits the class annotations
+ // visits the class annotations and type annotations
if (ANNOTATIONS && anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
@@ -639,6 +647,22 @@ public class ClassReader {
classVisitor.visitAnnotation(readUTF8(v, c), false));
}
}
+ if (ANNOTATIONS && tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ classVisitor.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (ANNOTATIONS && itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ classVisitor.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ }
// visits the attributes
while (attributes != null) {
@@ -697,6 +721,8 @@ public class ClassReader {
String signature = null;
int anns = 0;
int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
Object value = null;
Attribute attributes = null;
@@ -718,8 +744,14 @@ public class ClassReader {
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
} else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
+ } else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
} else {
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
readInt(u + 4), c, -1, null);
@@ -739,7 +771,7 @@ public class ClassReader {
return u;
}
- // visits the field annotations
+ // visits the field annotations and type annotations
if (ANNOTATIONS && anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
v = readAnnotationValues(v + 2, c, true,
@@ -752,6 +784,22 @@ public class ClassReader {
fv.visitAnnotation(readUTF8(v, c), false));
}
}
+ if (ANNOTATIONS && tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ fv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (ANNOTATIONS && itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ fv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ }
// visits the field attributes
while (attributes != null) {
@@ -782,9 +830,9 @@ public class ClassReader {
final Context context, int u) {
// reads the method declaration
char[] c = context.buffer;
- int access = readUnsignedShort(u);
- String name = readUTF8(u + 2, c);
- String desc = readUTF8(u + 4, c);
+ context.access = readUnsignedShort(u);
+ context.name = readUTF8(u + 2, c);
+ context.desc = readUTF8(u + 4, c);
u += 6;
// reads the method attributes
@@ -792,8 +840,11 @@ public class ClassReader {
int exception = 0;
String[] exceptions = null;
String signature = null;
+ int methodParameters = 0;
int anns = 0;
int ianns = 0;
+ int tanns = 0;
+ int itanns = 0;
int dann = 0;
int mpanns = 0;
int impanns = 0;
@@ -818,24 +869,32 @@ public class ClassReader {
} else if (SIGNATURES && "Signature".equals(attrName)) {
signature = readUTF8(u + 8, c);
} else if ("Deprecated".equals(attrName)) {
- access |= Opcodes.ACC_DEPRECATED;
+ context.access |= Opcodes.ACC_DEPRECATED;
} else if (ANNOTATIONS
&& "RuntimeVisibleAnnotations".equals(attrName)) {
anns = u + 8;
+ } else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = u + 8;
} else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) {
dann = u + 8;
} else if ("Synthetic".equals(attrName)) {
- access |= Opcodes.ACC_SYNTHETIC
+ context.access |= Opcodes.ACC_SYNTHETIC
| ClassWriter.ACC_SYNTHETIC_ATTRIBUTE;
} else if (ANNOTATIONS
&& "RuntimeInvisibleAnnotations".equals(attrName)) {
ianns = u + 8;
} else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = u + 8;
+ } else if (ANNOTATIONS
&& "RuntimeVisibleParameterAnnotations".equals(attrName)) {
mpanns = u + 8;
} else if (ANNOTATIONS
&& "RuntimeInvisibleParameterAnnotations".equals(attrName)) {
impanns = u + 8;
+ } else if ("MethodParameters".equals(attrName)) {
+ methodParameters = u + 8;
} else {
Attribute attr = readAttribute(context.attrs, attrName, u + 8,
readInt(u + 4), c, -1, null);
@@ -849,8 +908,8 @@ public class ClassReader {
u += 2;
// visits the method declaration
- MethodVisitor mv = classVisitor.visitMethod(access, name, desc,
- signature, exceptions);
+ MethodVisitor mv = classVisitor.visitMethod(context.access,
+ context.name, context.desc, signature, exceptions);
if (mv == null) {
return u;
}
@@ -894,6 +953,13 @@ public class ClassReader {
}
}
+ // visit the method parameters
+ if (methodParameters != 0) {
+ for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
+ mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
+ }
+ }
+
// visits the method annotations
if (ANNOTATIONS && dann != 0) {
AnnotationVisitor dv = mv.visitAnnotationDefault();
@@ -914,11 +980,27 @@ public class ClassReader {
mv.visitAnnotation(readUTF8(v, c), false));
}
}
+ if (ANNOTATIONS && tanns != 0) {
+ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ }
+ if (ANNOTATIONS && itanns != 0) {
+ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
+ v = readAnnotationTarget(context, v);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitTypeAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ }
if (ANNOTATIONS && mpanns != 0) {
- readParameterAnnotations(mpanns, desc, c, true, mv);
+ readParameterAnnotations(mv, context, mpanns, true);
}
if (ANNOTATIONS && impanns != 0) {
- readParameterAnnotations(impanns, desc, c, false, mv);
+ readParameterAnnotations(mv, context, impanns, false);
}
// visits the method attributes
@@ -931,9 +1013,6 @@ public class ClassReader {
// visits the method code
if (code != 0) {
- context.access = access;
- context.name = name;
- context.desc = desc;
mv.visitCode();
readCode(mv, context, code);
}
@@ -966,7 +1045,7 @@ public class ClassReader {
// reads the bytecode to find the labels
int codeStart = u;
int codeEnd = u + codeLength;
- Label[] labels = new Label[codeLength + 2];
+ Label[] labels = context.labels = new Label[codeLength + 2];
readLabel(codeLength + 1, labels);
while (u < codeEnd) {
int offset = u - codeStart;
@@ -1049,6 +1128,12 @@ public class ClassReader {
u += 2;
// reads the code attributes
+ int[] tanns = null; // start index of each visible type annotation
+ int[] itanns = null; // start index of each invisible type annotation
+ int tann = 0; // current index in tanns array
+ int itann = 0; // current index in itanns array
+ int ntoff = -1; // next visible type annotation code offset
+ int nitoff = -1; // next invisible type annotation code offset
int varTable = 0;
int varTypeTable = 0;
boolean zip = true;
@@ -1089,6 +1174,16 @@ public class ClassReader {
v += 4;
}
}
+ } else if (ANNOTATIONS
+ && "RuntimeVisibleTypeAnnotations".equals(attrName)) {
+ tanns = readTypeAnnotations(mv, context, u + 8, true);
+ ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1
+ : readUnsignedShort(tanns[0] + 1);
+ } else if (ANNOTATIONS
+ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) {
+ itanns = readTypeAnnotations(mv, context, u + 8, false);
+ nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1
+ : readUnsignedShort(itanns[0] + 1);
} else if (FRAMES && "StackMapTable".equals(attrName)) {
if ((context.flags & SKIP_FRAMES) == 0) {
stackMap = u + 10;
@@ -1211,7 +1306,7 @@ public class ClassReader {
}
}
if (frameCount > 0) {
- stackMap = readFrame(stackMap, zip, unzip, labels, frame);
+ stackMap = readFrame(stackMap, zip, unzip, frame);
--frameCount;
} else {
frame = null;
@@ -1310,6 +1405,7 @@ public class ClassReader {
case ClassWriter.FIELDORMETH_INSN:
case ClassWriter.ITFMETH_INSN: {
int cpIndex = items[readUnsignedShort(u + 1)];
+ boolean itf = b[cpIndex - 1] == ClassWriter.IMETH;
String iowner = readClass(cpIndex, c);
cpIndex = items[readUnsignedShort(cpIndex + 2)];
String iname = readUTF8(cpIndex, c);
@@ -1317,7 +1413,7 @@ public class ClassReader {
if (opcode < Opcodes.INVOKEVIRTUAL) {
mv.visitFieldInsn(opcode, iowner, iname, idesc);
} else {
- mv.visitMethodInsn(opcode, iowner, iname, idesc);
+ mv.visitMethodInsn(opcode, iowner, iname, idesc, itf);
}
if (opcode == Opcodes.INVOKEINTERFACE) {
u += 5;
@@ -1358,6 +1454,29 @@ public class ClassReader {
u += 4;
break;
}
+
+ // visit the instruction annotations, if any
+ while (tanns != null && tann < tanns.length && ntoff <= offset) {
+ if (ntoff == offset) {
+ int v = readAnnotationTarget(context, tanns[tann]);
+ readAnnotationValues(v + 2, c, true,
+ mv.visitInsnAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), true));
+ }
+ ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1
+ : readUnsignedShort(tanns[tann] + 1);
+ }
+ while (itanns != null && itann < itanns.length && nitoff <= offset) {
+ if (nitoff == offset) {
+ int v = readAnnotationTarget(context, itanns[itann]);
+ readAnnotationValues(v + 2, c, true,
+ mv.visitInsnAnnotation(context.typeRef,
+ context.typePath, readUTF8(v, c), false));
+ }
+ nitoff = ++itann >= itanns.length
+ || readByte(itanns[itann]) < 0x43 ? -1
+ : readUnsignedShort(itanns[itann] + 1);
+ }
}
if (labels[codeLength] != null) {
mv.visitLabel(labels[codeLength]);
@@ -1397,6 +1516,32 @@ public class ClassReader {
}
}
+ // visits the local variables type annotations
+ if (tanns != null) {
+ for (int i = 0; i < tanns.length; ++i) {
+ if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) {
+ int v = readAnnotationTarget(context, tanns[i]);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitLocalVariableAnnotation(context.typeRef,
+ context.typePath, context.start,
+ context.end, context.index, readUTF8(v, c),
+ true));
+ }
+ }
+ }
+ if (itanns != null) {
+ for (int i = 0; i < itanns.length; ++i) {
+ if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) {
+ int v = readAnnotationTarget(context, itanns[i]);
+ v = readAnnotationValues(v + 2, c, true,
+ mv.visitLocalVariableAnnotation(context.typeRef,
+ context.typePath, context.start,
+ context.end, context.index, readUTF8(v, c),
+ false));
+ }
+ }
+ }
+
// visits the code attributes
while (attributes != null) {
Attribute attr = attributes.next;
@@ -1410,24 +1555,175 @@ public class ClassReader {
}
/**
+ * Parses a type annotation table to find the labels, and to visit the try
+ * catch block annotations.
+ *
+ * @param u
+ * the start offset of a type annotation table.
+ * @param mv
+ * the method visitor to be used to visit the try catch block
+ * annotations.
+ * @param context
+ * information about the class being parsed.
+ * @param visible
+ * if the type annotation table to parse contains runtime visible
+ * annotations.
+ * @return the start offset of each type annotation in the parsed table.
+ */
+ private int[] readTypeAnnotations(final MethodVisitor mv,
+ final Context context, int u, boolean visible) {
+ char[] c = context.buffer;
+ int[] offsets = new int[readUnsignedShort(u)];
+ u += 2;
+ for (int i = 0; i < offsets.length; ++i) {
+ offsets[i] = u;
+ int target = readInt(u);
+ switch (target >>> 24) {
+ case 0x00: // CLASS_TYPE_PARAMETER
+ case 0x01: // METHOD_TYPE_PARAMETER
+ case 0x16: // METHOD_FORMAL_PARAMETER
+ u += 2;
+ break;
+ case 0x13: // FIELD
+ case 0x14: // METHOD_RETURN
+ case 0x15: // METHOD_RECEIVER
+ u += 1;
+ break;
+ case 0x40: // LOCAL_VARIABLE
+ case 0x41: // RESOURCE_VARIABLE
+ for (int j = readUnsignedShort(u + 1); j > 0; --j) {
+ int start = readUnsignedShort(u + 3);
+ int length = readUnsignedShort(u + 5);
+ readLabel(start, context.labels);
+ readLabel(start + length, context.labels);
+ u += 6;
+ }
+ u += 3;
+ break;
+ case 0x47: // CAST
+ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
+ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
+ u += 4;
+ break;
+ // case 0x10: // CLASS_EXTENDS
+ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
+ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
+ // case 0x17: // THROWS
+ // case 0x42: // EXCEPTION_PARAMETER
+ // case 0x43: // INSTANCEOF
+ // case 0x44: // NEW
+ // case 0x45: // CONSTRUCTOR_REFERENCE
+ // case 0x46: // METHOD_REFERENCE
+ default:
+ u += 3;
+ break;
+ }
+ int pathLength = readByte(u);
+ if ((target >>> 24) == 0x42) {
+ TypePath path = pathLength == 0 ? null : new TypePath(b, u);
+ u += 1 + 2 * pathLength;
+ u = readAnnotationValues(u + 2, c, true,
+ mv.visitTryCatchAnnotation(target, path,
+ readUTF8(u, c), visible));
+ } else {
+ u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null);
+ }
+ }
+ return offsets;
+ }
+
+ /**
+ * Parses the header of a type annotation to extract its target_type and
+ * target_path (the result is stored in the given context), and returns the
+ * start offset of the rest of the type_annotation structure (i.e. the
+ * offset to the type_index field, which is followed by
+ * num_element_value_pairs and then the name,value pairs).
+ *
+ * @param context
+ * information about the class being parsed. This is where the
+ * extracted target_type and target_path must be stored.
+ * @param u
+ * the start offset of a type_annotation structure.
+ * @return the start offset of the rest of the type_annotation structure.
+ */
+ private int readAnnotationTarget(final Context context, int u) {
+ int target = readInt(u);
+ switch (target >>> 24) {
+ case 0x00: // CLASS_TYPE_PARAMETER
+ case 0x01: // METHOD_TYPE_PARAMETER
+ case 0x16: // METHOD_FORMAL_PARAMETER
+ target &= 0xFFFF0000;
+ u += 2;
+ break;
+ case 0x13: // FIELD
+ case 0x14: // METHOD_RETURN
+ case 0x15: // METHOD_RECEIVER
+ target &= 0xFF000000;
+ u += 1;
+ break;
+ case 0x40: // LOCAL_VARIABLE
+ case 0x41: { // RESOURCE_VARIABLE
+ target &= 0xFF000000;
+ int n = readUnsignedShort(u + 1);
+ context.start = new Label[n];
+ context.end = new Label[n];
+ context.index = new int[n];
+ u += 3;
+ for (int i = 0; i < n; ++i) {
+ int start = readUnsignedShort(u);
+ int length = readUnsignedShort(u + 2);
+ context.start[i] = readLabel(start, context.labels);
+ context.end[i] = readLabel(start + length, context.labels);
+ context.index[i] = readUnsignedShort(u + 4);
+ u += 6;
+ }
+ break;
+ }
+ case 0x47: // CAST
+ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
+ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
+ target &= 0xFF0000FF;
+ u += 4;
+ break;
+ // case 0x10: // CLASS_EXTENDS
+ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
+ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
+ // case 0x17: // THROWS
+ // case 0x42: // EXCEPTION_PARAMETER
+ // case 0x43: // INSTANCEOF
+ // case 0x44: // NEW
+ // case 0x45: // CONSTRUCTOR_REFERENCE
+ // case 0x46: // METHOD_REFERENCE
+ default:
+ target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000;
+ u += 3;
+ break;
+ }
+ int pathLength = readByte(u);
+ context.typeRef = target;
+ context.typePath = pathLength == 0 ? null : new TypePath(b, u);
+ return u + 1 + 2 * pathLength;
+ }
+
+ /**
* Reads parameter annotations and makes the given visitor visit them.
*
+ * @param mv
+ * the visitor that must visit the annotations.
+ * @param context
+ * information about the class being parsed.
* @param v
* start offset in {@link #b b} of the annotations to be read.
- * @param desc
- * the method descriptor.
- * @param buf
- * buffer to be used to call {@link #readUTF8 readUTF8},
- * {@link #readClass(int,char[]) readClass} or {@link #readConst
- * readConst}.
* @param visible
* <tt>true</tt> if the annotations to be read are visible at
* runtime.
- * @param mv
- * the visitor that must visit the annotations.
*/
- private void readParameterAnnotations(int v, final String desc,
- final char[] buf, final boolean visible, final MethodVisitor mv) {
+ private void readParameterAnnotations(final MethodVisitor mv,
+ final Context context, int v, final boolean visible) {
int i;
int n = b[v++] & 0xFF;
// workaround for a bug in javac (javac compiler generates a parameter
@@ -1436,7 +1732,7 @@ public class ClassReader {
// equal to the number of parameters in the method descriptor - which
// includes the synthetic parameters added by the compiler). This work-
// around supposes that the synthetic parameters are the first ones.
- int synthetics = Type.getArgumentTypes(desc).length - n;
+ int synthetics = Type.getArgumentTypes(context.desc).length - n;
AnnotationVisitor av;
for (i = 0; i < synthetics; ++i) {
// virtual annotation to detect synthetic parameters in MethodWriter
@@ -1445,12 +1741,13 @@ public class ClassReader {
av.visitEnd();
}
}
+ char[] c = context.buffer;
for (; i < n + synthetics; ++i) {
int j = readUnsignedShort(v);
v += 2;
for (; j > 0; --j) {
- av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible);
- v = readAnnotationValues(v + 2, buf, true, av);
+ av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible);
+ v = readAnnotationValues(v + 2, c, true, av);
}
}
}
@@ -1729,17 +2026,14 @@ public class ClassReader {
* if the stack map frame at stackMap is compressed or not.
* @param unzip
* if the stack map frame must be uncompressed.
- * @param labels
- * the labels of the method currently being parsed, indexed by
- * their offset. A new label for the parsed stack map frame is
- * stored in this array if it does not already exist.
* @param frame
* where the parsed stack map frame must be stored.
* @return the offset of the first byte following the parsed frame.
*/
private int readFrame(int stackMap, boolean zip, boolean unzip,
- Label[] labels, Context frame) {
+ Context frame) {
char[] c = frame.buffer;
+ Label[] labels = frame.labels;
int tag;
int delta;
if (zip) {
diff --git a/src/asm/scala/tools/asm/ClassVisitor.java b/src/asm/scala/tools/asm/ClassVisitor.java
index 3fc364d5e5..48dc2ca6ae 100644
--- a/src/asm/scala/tools/asm/ClassVisitor.java
+++ b/src/asm/scala/tools/asm/ClassVisitor.java
@@ -33,8 +33,9 @@ package scala.tools.asm;
* A visitor to visit a Java class. The methods of this class must be called in
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
* <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
- * <tt>visitAttribute</tt> )* ( <tt>visitInnerClass</tt> | <tt>visitField</tt> |
- * <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
+ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
+ * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
+ * <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
@@ -42,7 +43,7 @@ public abstract class ClassVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -57,7 +58,7 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public ClassVisitor(final int api) {
this(api, null);
@@ -68,13 +69,13 @@ public abstract class ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param cv
* the class visitor to which this visitor must delegate method
* calls. May be null.
*/
public ClassVisitor(final int api, final ClassVisitor cv) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
@@ -169,6 +170,39 @@ public abstract class ClassVisitor {
}
/**
+ * Visits an annotation on a type in the class signature.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
+ * CLASS_TYPE_PARAMETER},
+ * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
+ * CLASS_TYPE_PARAMETER_BOUND} or
+ * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
+ * {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (cv != null) {
+ return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a non standard attribute of the class.
*
* @param attr
diff --git a/src/asm/scala/tools/asm/ClassWriter.java b/src/asm/scala/tools/asm/ClassWriter.java
index 93ed7313c7..5c2de3f982 100644
--- a/src/asm/scala/tools/asm/ClassWriter.java
+++ b/src/asm/scala/tools/asm/ClassWriter.java
@@ -417,6 +417,16 @@ public class ClassWriter extends ClassVisitor {
private AnnotationWriter ianns;
/**
+ * The runtime visible type annotations of this class.
+ */
+ private AnnotationWriter tanns;
+
+ /**
+ * The runtime invisible type annotations of this class.
+ */
+ private AnnotationWriter itanns;
+
+ /**
* The non standard attributes of this class.
*/
private Attribute attrs;
@@ -477,12 +487,12 @@ public class ClassWriter extends ClassVisitor {
* <tt>true</tt> if the maximum stack size and number of local variables
* must be automatically computed.
*/
- private final boolean computeMaxs;
+ private boolean computeMaxs;
/**
* <tt>true</tt> if the stack map frames must be recomputed from scratch.
*/
- private final boolean computeFrames;
+ private boolean computeFrames;
/**
* <tt>true</tt> if the stack map tables of this class are invalid. The
@@ -595,7 +605,7 @@ public class ClassWriter extends ClassVisitor {
* {@link #COMPUTE_FRAMES}.
*/
public ClassWriter(final int flags) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
index = 1;
pool = new ByteVector();
items = new Item[256];
@@ -677,7 +687,8 @@ public class ClassWriter extends ClassVisitor {
sourceFile = newUTF8(file);
}
if (debug != null) {
- sourceDebug = new ByteVector().putUTF8(debug);
+ sourceDebug = new ByteVector().encodeUTF8(debug, 0,
+ Integer.MAX_VALUE);
}
}
@@ -711,6 +722,29 @@ public class ClassWriter extends ClassVisitor {
}
@Override
+ public final AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, final String desc, final boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public final void visitAttribute(final Attribute attr) {
attr.next = attrs;
attrs = attr;
@@ -722,11 +756,29 @@ public class ClassWriter extends ClassVisitor {
if (innerClasses == null) {
innerClasses = new ByteVector();
}
- ++innerClassesCount;
- innerClasses.putShort(name == null ? 0 : newClass(name));
- innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
- innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
- innerClasses.putShort(access);
+ // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
+ // constant_pool table which represents a class or interface C that is
+ // not a package member must have exactly one corresponding entry in the
+ // classes array". To avoid duplicates we keep track in the intVal field
+ // of the Item of each CONSTANT_Class_info entry C whether an inner
+ // class entry has already been added for C (this field is unused for
+ // class entries, and changing its value does not change the hashcode
+ // and equality tests). If so we store the index of this inner class
+ // entry (plus one) in intVal. This hack allows duplicate detection in
+ // O(1) time.
+ Item nameItem = newClassItem(name);
+ if (nameItem.intVal == 0) {
+ ++innerClassesCount;
+ innerClasses.putShort(nameItem.index);
+ innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
+ innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
+ innerClasses.putShort(access);
+ nameItem.intVal = innerClassesCount;
+ } else {
+ // Compare the inner classes entry nameItem.intVal - 1 with the
+ // arguments of this method and throw an exception if there is a
+ // difference?
+ }
}
@Override
@@ -795,7 +847,7 @@ public class ClassWriter extends ClassVisitor {
}
if (sourceDebug != null) {
++attributeCount;
- size += sourceDebug.length + 4;
+ size += sourceDebug.length + 6;
newUTF8("SourceDebugExtension");
}
if (enclosingMethodOwner != 0) {
@@ -831,6 +883,16 @@ public class ClassWriter extends ClassVisitor {
size += 8 + ianns.getSize();
newUTF8("RuntimeInvisibleAnnotations");
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ ++attributeCount;
+ size += 8 + tanns.getSize();
+ newUTF8("RuntimeVisibleTypeAnnotations");
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ ++attributeCount;
+ size += 8 + itanns.getSize();
+ newUTF8("RuntimeInvisibleTypeAnnotations");
+ }
if (attrs != null) {
attributeCount += attrs.getCount();
size += attrs.getSize(this, null, 0, -1, -1);
@@ -874,9 +936,9 @@ public class ClassWriter extends ClassVisitor {
out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
}
if (sourceDebug != null) {
- int len = sourceDebug.length - 2;
+ int len = sourceDebug.length;
out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
- out.putByteArray(sourceDebug.data, 2, len);
+ out.putByteArray(sourceDebug.data, 0, len);
}
if (enclosingMethodOwner != 0) {
out.putShort(newUTF8("EnclosingMethod")).putInt(4);
@@ -904,13 +966,34 @@ public class ClassWriter extends ClassVisitor {
out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
if (attrs != null) {
attrs.put(this, null, 0, -1, -1, out);
}
if (invalidFrames) {
- ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
- new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES);
- return cw.toByteArray();
+ anns = null;
+ ianns = null;
+ attrs = null;
+ innerClassesCount = 0;
+ innerClasses = null;
+ bootstrapMethodsCount = 0;
+ bootstrapMethods = null;
+ firstField = null;
+ lastField = null;
+ firstMethod = null;
+ lastMethod = null;
+ computeMaxs = false;
+ computeFrames = true;
+ invalidFrames = false;
+ new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
+ return toByteArray();
}
return out.data;
}
@@ -1577,7 +1660,7 @@ public class ClassWriter extends ClassVisitor {
/**
* Returns the common super type of the two given types. The default
- * implementation of this method <i>loads<i> the two given classes and uses
+ * implementation of this method <i>loads</i> the two given classes and uses
* the java.lang.Class methods to find the common super class. It can be
* overridden to compute this common super type in other ways, in particular
* without actually loading any class, or to take into account the class
@@ -1664,6 +1747,15 @@ public class ClassWriter extends ClassVisitor {
}
/**
+ * Find item that whose index is `index`.
+ */
+ public Item findItemByIndex(int index) {
+ int i = 0;
+ while (i < items.length && (items[i] == null || items[i].index != index)) i++;
+ return items[i];
+ }
+
+ /**
* Puts one byte and two shorts into the constant pool.
*
* @param b
diff --git a/src/asm/scala/tools/asm/Context.java b/src/asm/scala/tools/asm/Context.java
index 7b3a2ad9dd..24546969e3 100644
--- a/src/asm/scala/tools/asm/Context.java
+++ b/src/asm/scala/tools/asm/Context.java
@@ -73,11 +73,46 @@ class Context {
String desc;
/**
+ * The label objects, indexed by bytecode offset, of the method currently
+ * being parsed (only bytecode offsets for which a label is needed have a
+ * non null associated Label object).
+ */
+ Label[] labels;
+
+ /**
+ * The target of the type annotation currently being parsed.
+ */
+ int typeRef;
+
+ /**
+ * The path of the type annotation currently being parsed.
+ */
+ TypePath typePath;
+
+ /**
* The offset of the latest stack map frame that has been parsed.
*/
int offset;
/**
+ * The labels corresponding to the start of the local variable ranges in the
+ * local variable type annotation currently being parsed.
+ */
+ Label[] start;
+
+ /**
+ * The labels corresponding to the end of the local variable ranges in the
+ * local variable type annotation currently being parsed.
+ */
+ Label[] end;
+
+ /**
+ * The local variable indices for each local variable range in the local
+ * variable type annotation currently being parsed.
+ */
+ int[] index;
+
+ /**
* The encoding of the latest stack map frame that has been parsed.
*/
int mode;
diff --git a/src/asm/scala/tools/asm/CustomAttr.java b/src/asm/scala/tools/asm/CustomAttr.java
index 22b5d287b7..5ecfd283d0 100644
--- a/src/asm/scala/tools/asm/CustomAttr.java
+++ b/src/asm/scala/tools/asm/CustomAttr.java
@@ -1,5 +1,5 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2013 LAMP/EPFL
+ * Copyright 2005-2012 LAMP/EPFL
*/
package scala.tools.asm;
diff --git a/src/asm/scala/tools/asm/FieldVisitor.java b/src/asm/scala/tools/asm/FieldVisitor.java
index 9171f331e5..708c1d322e 100644
--- a/src/asm/scala/tools/asm/FieldVisitor.java
+++ b/src/asm/scala/tools/asm/FieldVisitor.java
@@ -31,8 +31,8 @@ package scala.tools.asm;
/**
* A visitor to visit a Java field. The methods of this class must be called in
- * the following order: ( <tt>visitAnnotation</tt> | <tt>visitAttribute</tt> )*
- * <tt>visitEnd</tt>.
+ * the following order: ( <tt>visitAnnotation</tt> |
+ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
@@ -40,7 +40,7 @@ public abstract class FieldVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -55,7 +55,7 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public FieldVisitor(final int api) {
this(api, null);
@@ -66,13 +66,13 @@ public abstract class FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param fv
* the field visitor to which this visitor must delegate method
* calls. May be null.
*/
public FieldVisitor(final int api, final FieldVisitor fv) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
@@ -97,6 +97,35 @@ public abstract class FieldVisitor {
}
/**
+ * Visits an annotation on the type of the field.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#FIELD FIELD}. See
+ * {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (fv != null) {
+ return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a non standard attribute of the field.
*
* @param attr
diff --git a/src/asm/scala/tools/asm/FieldWriter.java b/src/asm/scala/tools/asm/FieldWriter.java
index 02c6059b91..e640a8d406 100644
--- a/src/asm/scala/tools/asm/FieldWriter.java
+++ b/src/asm/scala/tools/asm/FieldWriter.java
@@ -81,6 +81,17 @@ final class FieldWriter extends FieldVisitor {
private AnnotationWriter ianns;
/**
+ * The runtime visible type annotations of this field. May be <tt>null</tt>.
+ */
+ private AnnotationWriter tanns;
+
+ /**
+ * The runtime invisible type annotations of this field. May be
+ * <tt>null</tt>.
+ */
+ private AnnotationWriter itanns;
+
+ /**
* The non standard attributes of this field. May be <tt>null</tt>.
*/
private Attribute attrs;
@@ -107,7 +118,7 @@ final class FieldWriter extends FieldVisitor {
*/
FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
if (cw.firstField == null) {
cw.firstField = this;
} else {
@@ -151,6 +162,29 @@ final class FieldWriter extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
attr.next = attrs;
attrs = attr;
@@ -198,6 +232,14 @@ final class FieldWriter extends FieldVisitor {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ cw.newUTF8("RuntimeVisibleTypeAnnotations");
+ size += 8 + tanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ cw.newUTF8("RuntimeInvisibleTypeAnnotations");
+ size += 8 + itanns.getSize();
+ }
if (attrs != null) {
size += attrs.getSize(cw, null, 0, -1, -1);
}
@@ -237,6 +279,12 @@ final class FieldWriter extends FieldVisitor {
if (ClassReader.ANNOTATIONS && ianns != null) {
++attributeCount;
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ ++attributeCount;
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ ++attributeCount;
+ }
if (attrs != null) {
attributeCount += attrs.getCount();
}
@@ -266,6 +314,14 @@ final class FieldWriter extends FieldVisitor {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out);
}
diff --git a/src/asm/scala/tools/asm/Frame.java b/src/asm/scala/tools/asm/Frame.java
index bcc3e8450b..85ad3269ab 100644
--- a/src/asm/scala/tools/asm/Frame.java
+++ b/src/asm/scala/tools/asm/Frame.java
@@ -70,8 +70,8 @@ final class Frame {
* stack types. VALUE depends on KIND. For LOCAL types, it is an index in
* the input local variable types. For STACK types, it is a position
* relatively to the top of input frame stack. For BASE types, it is either
- * one of the constants defined in FrameVisitor, or for OBJECT and
- * UNINITIALIZED types, a tag and an index in the type table.
+ * one of the constants defined below, or for OBJECT and UNINITIALIZED
+ * types, a tag and an index in the type table.
*
* Output frames can contain types of any kind and with a positive or
* negative dimension (and even unassigned types, represented by 0 - which
@@ -1417,6 +1417,7 @@ final class Frame {
// if t is the NULL type, merge(u,t)=u, so there is no change
return false;
} else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) {
+ // if t and u have the same dimension and same base kind
if ((u & BASE_KIND) == OBJECT) {
// if t is also a reference type, and if u and t have the
// same dimension merge(u,t) = dim(t) | common parent of the
@@ -1425,13 +1426,21 @@ final class Frame {
| cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
} else {
// if u and t are array types, but not with the same element
- // type, merge(u,t)=java/lang/Object
- v = OBJECT | cw.addType("java/lang/Object");
+ // type, merge(u,t) = dim(u) - 1 | java/lang/Object
+ int vdim = ELEMENT_OF + (u & DIM);
+ v = vdim | OBJECT | cw.addType("java/lang/Object");
}
} else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
- // if t is any other reference or array type,
- // merge(u,t)=java/lang/Object
- v = OBJECT | cw.addType("java/lang/Object");
+ // if t is any other reference or array type, the merged type
+ // is min(udim, tdim) | java/lang/Object, where udim is the
+ // array dimension of u, minus 1 if u is an array type with a
+ // primitive element type (and similarly for tdim).
+ int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0
+ : ELEMENT_OF) + (t & DIM);
+ int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0
+ : ELEMENT_OF) + (u & DIM);
+ v = Math.min(tdim, udim) | OBJECT
+ | cw.addType("java/lang/Object");
} else {
// if t is any other type, merge(u,t)=TOP
v = TOP;
diff --git a/src/asm/scala/tools/asm/Handle.java b/src/asm/scala/tools/asm/Handle.java
index 5dd06a54b9..cf12bb7613 100644
--- a/src/asm/scala/tools/asm/Handle.java
+++ b/src/asm/scala/tools/asm/Handle.java
@@ -49,7 +49,8 @@ public final class Handle {
final int tag;
/**
- * The internal name of the field or method designed by this handle.
+ * The internal name of the class that owns the field or method designated
+ * by this handle.
*/
final String owner;
@@ -76,8 +77,8 @@ public final class Handle {
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
- * the internal name of the field or method designed by this
- * handle.
+ * the internal name of the class that owns the field or method
+ * designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
@@ -106,9 +107,11 @@ public final class Handle {
}
/**
- * Returns the internal name of the field or method designed by this handle.
+ * Returns the internal name of the class that owns the field or method
+ * designated by this handle.
*
- * @return the internal name of the field or method designed by this handle.
+ * @return the internal name of the class that owns the field or method
+ * designated by this handle.
*/
public String getOwner() {
return owner;
diff --git a/src/asm/scala/tools/asm/Item.java b/src/asm/scala/tools/asm/Item.java
index 94195a1082..4693f5ae99 100644
--- a/src/asm/scala/tools/asm/Item.java
+++ b/src/asm/scala/tools/asm/Item.java
@@ -208,9 +208,10 @@ final class Item {
this.strVal2 = strVal2;
this.strVal3 = strVal3;
switch (type) {
+ case ClassWriter.CLASS:
+ this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
case ClassWriter.UTF8:
case ClassWriter.STR:
- case ClassWriter.CLASS:
case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
diff --git a/src/asm/scala/tools/asm/MethodVisitor.java b/src/asm/scala/tools/asm/MethodVisitor.java
index e43ca97823..bddc325020 100644
--- a/src/asm/scala/tools/asm/MethodVisitor.java
+++ b/src/asm/scala/tools/asm/MethodVisitor.java
@@ -31,18 +31,24 @@ package scala.tools.asm;
/**
* A visitor to visit a Java method. The methods of this class must be called in
- * the following order: [ <tt>visitAnnotationDefault</tt> ] (
- * <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> |
- * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
- * <tt>visit</tt><i>X</i>Insn</tt> | <tt>visitLabel</tt> |
- * <tt>visitTryCatchBlock</tt> | <tt>visitLocalVariable</tt> |
+ * the following order: ( <tt>visitParameter</tt> )* [
+ * <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> |
+ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* [
+ * <tt>visitCode</tt> ( <tt>visitFrame</tt> | <tt>visit<i>X</i>Insn</tt> |
+ * <tt>visitLabel</tt> | <tt>visitInsnAnnotation</tt> |
+ * <tt>visitTryCatchBlock</tt> | <tt>visitTryCatchBlockAnnotation</tt> |
+ * <tt>visitLocalVariable</tt> | <tt>visitLocalVariableAnnotation</tt> |
* <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In
- * addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt> methods
- * must be called in the sequential order of the bytecode instructions of the
- * visited code, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
- * labels passed as arguments have been visited, and the
- * <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> methods must be
- * called <i>after</i> the labels passed as arguments have been visited.
+ * addition, the <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must
+ * be called in the sequential order of the bytecode instructions of the visited
+ * code, <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated
+ * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
+ * labels passed as arguments have been visited,
+ * <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the
+ * corresponding try catch block has been visited, and the
+ * <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and
+ * <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels
+ * passed as arguments have been visited.
*
* @author Eric Bruneton
*/
@@ -50,7 +56,7 @@ public abstract class MethodVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -65,7 +71,7 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public MethodVisitor(final int api) {
this(api, null);
@@ -76,13 +82,13 @@ public abstract class MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param mv
* the method visitor to which this visitor must delegate method
* calls. May be null.
*/
public MethodVisitor(final int api, final MethodVisitor mv) {
- if (api != Opcodes.ASM4) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
throw new IllegalArgumentException();
}
this.api = api;
@@ -90,10 +96,29 @@ public abstract class MethodVisitor {
}
// -------------------------------------------------------------------------
- // Annotations and non standard attributes
+ // Parameters, annotations and non standard attributes
// -------------------------------------------------------------------------
/**
+ * Visits a parameter of this method.
+ *
+ * @param name
+ * parameter name or null if none is provided.
+ * @param access
+ * the parameter's access flags, only <tt>ACC_FINAL</tt>,
+ * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are
+ * allowed (see {@link Opcodes}).
+ */
+ public void visitParameter(String name, int access) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ mv.visitParameter(name, access);
+ }
+ }
+
+ /**
* Visits the default value of this annotation interface method.
*
* @return a visitor to the visit the actual default value of this
@@ -128,6 +153,42 @@ public abstract class MethodVisitor {
}
/**
+ * Visits an annotation on a type in the method signature.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#METHOD_TYPE_PARAMETER
+ * METHOD_TYPE_PARAMETER},
+ * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND
+ * METHOD_TYPE_PARAMETER_BOUND},
+ * {@link TypeReference#METHOD_RETURN METHOD_RETURN},
+ * {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link TypeReference#METHOD_FORMAL_PARAMETER
+ * METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS
+ * THROWS}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits an annotation of a parameter this method.
*
* @param parameter
@@ -201,9 +262,11 @@ public abstract class MethodVisitor {
* <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
* same as the locals in the previous frame, except that the last 1-3 locals
* are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
- * <li>{@link Opcodes#F_FULL} representing complete frame data.</li></li>
+ * <li>{@link Opcodes#F_FULL} representing complete frame data.</li>
+ * </ul>
+ * </li>
* </ul>
- * </ul> <br>
+ * <br>
* In both cases the first frame, corresponding to the method's parameters
* and access flags, is implicit and must not be visited. Also, it is
* illegal to visit two or more frames for the same code location (i.e., at
@@ -376,14 +439,53 @@ public abstract class MethodVisitor {
* @param desc
* the method's descriptor (see {@link Type Type}).
*/
+ @Deprecated
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
+ if (api >= Opcodes.ASM5) {
+ boolean itf = opcode == Opcodes.INVOKEINTERFACE;
+ visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
/**
+ * Visits a method instruction. A method instruction is an instruction that
+ * invokes a method.
+ *
+ * @param opcode
+ * the opcode of the type instruction to be visited. This opcode
+ * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
+ * INVOKEINTERFACE.
+ * @param owner
+ * the internal name of the method's owner class (see
+ * {@link Type#getInternalName() getInternalName}).
+ * @param name
+ * the method's name.
+ * @param desc
+ * the method's descriptor (see {@link Type Type}).
+ * @param itf
+ * if the method's owner class is an interface.
+ */
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
+ throw new IllegalArgumentException(
+ "INVOKESPECIAL/STATIC on interfaces require ASM 5");
+ }
+ visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
+ }
+
+ /**
* Visits an invokedynamic instruction.
*
* @param name
@@ -558,6 +660,48 @@ public abstract class MethodVisitor {
}
}
+ /**
+ * Visits an annotation on an instruction. This method must be called just
+ * <i>after</i> the annotated instruction. It can be called several times
+ * for the same instruction.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#INSTANCEOF INSTANCEOF},
+ * {@link TypeReference#NEW NEW},
+ * {@link TypeReference#CONSTRUCTOR_REFERENCE
+ * CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE
+ * METHOD_REFERENCE}, {@link TypeReference#CAST CAST},
+ * {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
// -------------------------------------------------------------------------
// Exceptions table entries, debug information, max stack and max locals
// -------------------------------------------------------------------------
@@ -587,6 +731,38 @@ public abstract class MethodVisitor {
}
/**
+ * Visits an annotation on an exception handler type. This method must be
+ * called <i>after</i> the {@link #visitTryCatchBlock} for the annotated
+ * exception handler. It can be called several times for the same exception
+ * handler.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#EXCEPTION_PARAMETER
+ * EXCEPTION_PARAMETER}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a local variable declaration.
*
* @param name
@@ -617,6 +793,48 @@ public abstract class MethodVisitor {
}
/**
+ * Visits an annotation on a local variable type.
+ *
+ * @param typeRef
+ * a reference to the annotated type. The sort of this type
+ * reference must be {@link TypeReference#LOCAL_VARIABLE
+ * LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE
+ * RESOURCE_VARIABLE}. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param start
+ * the fist instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (inclusive).
+ * @param end
+ * the last instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (exclusive). This
+ * array must have the same size as the 'start' array.
+ * @param index
+ * the local variable's index in each range. This array must have
+ * the same size as the 'start' array.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values, or <tt>null</tt> if
+ * this visitor is not interested in visiting this annotation.
+ */
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ if (api < Opcodes.ASM5) {
+ throw new RuntimeException();
+ }
+ if (mv != null) {
+ return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
+ end, index, desc, visible);
+ }
+ return null;
+ }
+
+ /**
* Visits a line number declaration.
*
* @param line
diff --git a/src/asm/scala/tools/asm/MethodWriter.java b/src/asm/scala/tools/asm/MethodWriter.java
index 87acab17c9..0c4130e499 100644
--- a/src/asm/scala/tools/asm/MethodWriter.java
+++ b/src/asm/scala/tools/asm/MethodWriter.java
@@ -192,6 +192,18 @@ class MethodWriter extends MethodVisitor {
private AnnotationWriter ianns;
/**
+ * The runtime visible type annotations of this method. May be <tt>null</tt>
+ * .
+ */
+ private AnnotationWriter tanns;
+
+ /**
+ * The runtime invisible type annotations of this method. May be
+ * <tt>null</tt>.
+ */
+ private AnnotationWriter itanns;
+
+ /**
* The runtime visible parameter annotations of this method. May be
* <tt>null</tt>.
*/
@@ -283,6 +295,16 @@ class MethodWriter extends MethodVisitor {
private Handler lastHandler;
/**
+ * Number of entries in the MethodParameters attribute.
+ */
+ private int methodParametersCount;
+
+ /**
+ * The MethodParameters attribute.
+ */
+ private ByteVector methodParameters;
+
+ /**
* Number of entries in the LocalVariableTable attribute.
*/
private int localVarCount;
@@ -313,6 +335,21 @@ class MethodWriter extends MethodVisitor {
private ByteVector lineNumber;
/**
+ * The start offset of the last visited instruction.
+ */
+ private int lastCodeOffset;
+
+ /**
+ * The runtime visible type annotations of the code. May be <tt>null</tt>.
+ */
+ private AnnotationWriter ctanns;
+
+ /**
+ * The runtime invisible type annotations of the code. May be <tt>null</tt>.
+ */
+ private AnnotationWriter ictanns;
+
+ /**
* The non standard attributes of the method's code.
*/
private Attribute cattrs;
@@ -416,7 +453,7 @@ class MethodWriter extends MethodVisitor {
final String desc, final String signature,
final String[] exceptions, final boolean computeMaxs,
final boolean computeFrames) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
if (cw.firstMethod == null) {
cw.firstMethod = this;
} else {
@@ -462,6 +499,16 @@ class MethodWriter extends MethodVisitor {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(String name, int access) {
+ if (methodParameters == null) {
+ methodParameters = new ByteVector();
+ }
+ ++methodParametersCount;
+ methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name))
+ .putShort(access);
+ }
+
+ @Override
public AnnotationVisitor visitAnnotationDefault() {
if (!ClassReader.ANNOTATIONS) {
return null;
@@ -491,6 +538,29 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = tanns;
+ tanns = aw;
+ } else {
+ aw.next = itanns;
+ itanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
@@ -642,6 +712,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitInsn(final int opcode) {
+ lastCodeOffset = code.length;
// adds the instruction to the bytecode of the method
code.putByte(opcode);
// update currentBlock
@@ -667,6 +738,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitIntInsn(final int opcode, final int operand) {
+ lastCodeOffset = code.length;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
@@ -691,6 +763,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitVarInsn(final int opcode, final int var) {
+ lastCodeOffset = code.length;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
@@ -749,6 +822,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitTypeInsn(final int opcode, final String type) {
+ lastCodeOffset = code.length;
Item i = cw.newClassItem(type);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -771,6 +845,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
+ lastCodeOffset = code.length;
Item i = cw.newFieldItem(owner, name, desc);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -808,8 +883,8 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
- boolean itf = opcode == Opcodes.INVOKEINTERFACE;
+ final String name, final String desc, final boolean itf) {
+ lastCodeOffset = code.length;
Item i = cw.newMethodItem(owner, name, desc, itf);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
@@ -847,7 +922,7 @@ class MethodWriter extends MethodVisitor {
}
}
// adds the instruction to the bytecode of the method
- if (itf) {
+ if (opcode == Opcodes.INVOKEINTERFACE) {
if (argSize == 0) {
argSize = Type.getArgumentsAndReturnSizes(desc);
i.intVal = argSize;
@@ -861,6 +936,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitInvokeDynamicInsn(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
+ lastCodeOffset = code.length;
Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs);
int argSize = i.intVal;
// Label currentBlock = this.currentBlock;
@@ -900,6 +976,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitJumpInsn(final int opcode, final Label label) {
+ lastCodeOffset = code.length;
Label nextInsn = null;
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -1045,6 +1122,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitLdcInsn(final Object cst) {
+ lastCodeOffset = code.length;
Item i = cw.newConstItem(cst);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -1078,6 +1156,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitIincInsn(final int var, final int increment) {
+ lastCodeOffset = code.length;
if (currentBlock != null) {
if (compute == FRAMES) {
currentBlock.frame.execute(Opcodes.IINC, var, null, null);
@@ -1102,6 +1181,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
+ lastCodeOffset = code.length;
// adds the instruction to the bytecode of the method
int source = code.length;
code.putByte(Opcodes.TABLESWITCH);
@@ -1118,6 +1198,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
+ lastCodeOffset = code.length;
// adds the instruction to the bytecode of the method
int source = code.length;
code.putByte(Opcodes.LOOKUPSWITCH);
@@ -1160,6 +1241,7 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
+ lastCodeOffset = code.length;
Item i = cw.newClassItem(desc);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
@@ -1176,6 +1258,30 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8);
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = ctanns;
+ ctanns = aw;
+ } else {
+ aw.next = ictanns;
+ ictanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
++handlerCount;
@@ -1194,6 +1300,29 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ AnnotationWriter.putTarget(typeRef, typePath, bv);
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = ctanns;
+ ctanns = aw;
+ } else {
+ aw.next = ictanns;
+ ictanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -1226,6 +1355,41 @@ class MethodWriter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ if (!ClassReader.ANNOTATIONS) {
+ return null;
+ }
+ ByteVector bv = new ByteVector();
+ // write target_type and target_info
+ bv.putByte(typeRef >>> 24).putShort(start.length);
+ for (int i = 0; i < start.length; ++i) {
+ bv.putShort(start[i].position)
+ .putShort(end[i].position - start[i].position)
+ .putShort(index[i]);
+ }
+ if (typePath == null) {
+ bv.putByte(0);
+ } else {
+ int length = typePath.b[typePath.offset] * 2 + 1;
+ bv.putByteArray(typePath.b, typePath.offset, length);
+ }
+ // write type, and reserve space for values count
+ bv.putShort(cw.newUTF8(desc)).putShort(0);
+ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
+ bv.length - 2);
+ if (visible) {
+ aw.next = ctanns;
+ ctanns = aw;
+ } else {
+ aw.next = ictanns;
+ ictanns = aw;
+ }
+ return aw;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
if (lineNumber == null) {
lineNumber = new ByteVector();
@@ -1237,6 +1401,14 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
+ if (resize) {
+ // replaces the temporary jump opcodes introduced by Label.resolve.
+ if (ClassReader.RESIZE) {
+ resizeInstructions();
+ } else {
+ throw new RuntimeException("Method code too large!");
+ }
+ }
if (ClassReader.FRAMES && compute == FRAMES) {
// completes the control flow graph with exception handler blocks
Handler handler = firstHandler;
@@ -1858,22 +2030,12 @@ class MethodWriter extends MethodVisitor {
if (classReaderOffset != 0) {
return 6 + classReaderLength;
}
- if (resize) {
- // replaces the temporary jump opcodes introduced by Label.resolve.
- if (ClassReader.RESIZE) {
- resizeInstructions();
- } else {
- throw new RuntimeException("Method code too large!");
- }
- }
int size = 8;
if (code.length > 0) {
if (code.length > 65536) {
String nameString = "";
- int i = 0;
- // find item that corresponds to the index of our name
- while (i < cw.items.length && (cw.items[i] == null || cw.items[i].index != name)) i++;
- if (cw.items[i] != null) nameString = cw.items[i].strVal1 +"'s ";
+ Item nameItem = cw.findItemByIndex(name);
+ if (nameItem != null) nameString = nameItem.strVal1 +"'s ";
throw new RuntimeException("Method "+ nameString +"code too large!");
}
cw.newUTF8("Code");
@@ -1895,6 +2057,14 @@ class MethodWriter extends MethodVisitor {
cw.newUTF8(zip ? "StackMapTable" : "StackMap");
size += 8 + stackMap.length;
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ cw.newUTF8("RuntimeVisibleTypeAnnotations");
+ size += 8 + ctanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ cw.newUTF8("RuntimeInvisibleTypeAnnotations");
+ size += 8 + ictanns.getSize();
+ }
if (cattrs != null) {
size += cattrs.getSize(cw, code.data, code.length, maxStack,
maxLocals);
@@ -1920,6 +2090,10 @@ class MethodWriter extends MethodVisitor {
cw.newUTF8(signature);
size += 8;
}
+ if (methodParameters != null) {
+ cw.newUTF8("MethodParameters");
+ size += 7 + methodParameters.length;
+ }
if (ClassReader.ANNOTATIONS && annd != null) {
cw.newUTF8("AnnotationDefault");
size += 6 + annd.length;
@@ -1932,6 +2106,14 @@ class MethodWriter extends MethodVisitor {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ cw.newUTF8("RuntimeVisibleTypeAnnotations");
+ size += 8 + tanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ cw.newUTF8("RuntimeInvisibleTypeAnnotations");
+ size += 8 + itanns.getSize();
+ }
if (ClassReader.ANNOTATIONS && panns != null) {
cw.newUTF8("RuntimeVisibleParameterAnnotations");
size += 7 + 2 * (panns.length - synthetics);
@@ -1988,6 +2170,9 @@ class MethodWriter extends MethodVisitor {
if (ClassReader.SIGNATURES && signature != null) {
++attributeCount;
}
+ if (methodParameters != null) {
+ ++attributeCount;
+ }
if (ClassReader.ANNOTATIONS && annd != null) {
++attributeCount;
}
@@ -1997,6 +2182,12 @@ class MethodWriter extends MethodVisitor {
if (ClassReader.ANNOTATIONS && ianns != null) {
++attributeCount;
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ ++attributeCount;
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ ++attributeCount;
+ }
if (ClassReader.ANNOTATIONS && panns != null) {
++attributeCount;
}
@@ -2021,6 +2212,12 @@ class MethodWriter extends MethodVisitor {
if (stackMap != null) {
size += 8 + stackMap.length;
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ size += 8 + ctanns.getSize();
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ size += 8 + ictanns.getSize();
+ }
if (cattrs != null) {
size += cattrs.getSize(cw, code.data, code.length, maxStack,
maxLocals);
@@ -2050,6 +2247,12 @@ class MethodWriter extends MethodVisitor {
if (stackMap != null) {
++attributeCount;
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ ++attributeCount;
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ ++attributeCount;
+ }
if (cattrs != null) {
attributeCount += cattrs.getCount();
}
@@ -2075,6 +2278,14 @@ class MethodWriter extends MethodVisitor {
out.putInt(stackMap.length + 2).putShort(frameCount);
out.putByteArray(stackMap.data, 0, stackMap.length);
}
+ if (ClassReader.ANNOTATIONS && ctanns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
+ ctanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && ictanns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
+ ictanns.put(out);
+ }
if (cattrs != null) {
cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
}
@@ -2100,6 +2311,12 @@ class MethodWriter extends MethodVisitor {
out.putShort(cw.newUTF8("Signature")).putInt(2)
.putShort(cw.newUTF8(signature));
}
+ if (methodParameters != null) {
+ out.putShort(cw.newUTF8("MethodParameters"));
+ out.putInt(methodParameters.length + 1).putByte(
+ methodParametersCount);
+ out.putByteArray(methodParameters.data, 0, methodParameters.length);
+ }
if (ClassReader.ANNOTATIONS && annd != null) {
out.putShort(cw.newUTF8("AnnotationDefault"));
out.putInt(annd.length);
@@ -2113,6 +2330,14 @@ class MethodWriter extends MethodVisitor {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
+ if (ClassReader.ANNOTATIONS && tanns != null) {
+ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
+ tanns.put(out);
+ }
+ if (ClassReader.ANNOTATIONS && itanns != null) {
+ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
+ itanns.put(out);
+ }
if (ClassReader.ANNOTATIONS && panns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
AnnotationWriter.put(panns, synthetics, out);
@@ -2464,49 +2689,50 @@ class MethodWriter extends MethodVisitor {
}
}
- // recomputes the stack map frames
- if (frameCount > 0) {
- if (compute == FRAMES) {
- frameCount = 0;
- stackMap = null;
- previousFrame = null;
- frame = null;
- Frame f = new Frame();
- f.owner = labels;
- Type[] args = Type.getArgumentTypes(descriptor);
- f.initInputFrame(cw, access, args, maxLocals);
- visitFrame(f);
- Label l = labels;
- while (l != null) {
- /*
- * here we need the original label position. getNewOffset
- * must therefore never have been called for this label.
- */
- u = l.position - 3;
- if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) {
- getNewOffset(allIndexes, allSizes, l);
- // TODO update offsets in UNINITIALIZED values
- visitFrame(l.frame);
- }
- l = l.successor;
- }
- } else {
+ // updates the stack map frame labels
+ if (compute == FRAMES) {
+ Label l = labels;
+ while (l != null) {
/*
- * Resizing an existing stack map frame table is really hard.
- * Not only the table must be parsed to update the offets, but
- * new frames may be needed for jump instructions that were
- * inserted by this method. And updating the offsets or
- * inserting frames can change the format of the following
- * frames, in case of packed frames. In practice the whole table
- * must be recomputed. For this the frames are marked as
- * potentially invalid. This will cause the whole class to be
- * reread and rewritten with the COMPUTE_FRAMES option (see the
- * ClassWriter.toByteArray method). This is not very efficient
- * but is much easier and requires much less code than any other
- * method I can think of.
+ * Detects the labels that are just after an IF instruction that
+ * has been resized with the IFNOT GOTO_W pattern. These labels
+ * are now the target of a jump instruction (the IFNOT
+ * instruction). Note that we need the original label position
+ * here. getNewOffset must therefore never have been called for
+ * this label.
*/
- cw.invalidFrames = true;
+ u = l.position - 3;
+ if (u >= 0 && resize[u]) {
+ l.status |= Label.TARGET;
+ }
+ getNewOffset(allIndexes, allSizes, l);
+ l = l.successor;
}
+ // Update the offsets in the uninitialized types
+ for (i = 0; i < cw.typeTable.length; ++i) {
+ Item item = cw.typeTable[i];
+ if (item != null && item.type == ClassWriter.TYPE_UNINIT) {
+ item.intVal = getNewOffset(allIndexes, allSizes, 0,
+ item.intVal);
+ }
+ }
+ // The stack map frames are not serialized yet, so we don't need
+ // to update them. They will be serialized in visitMaxs.
+ } else if (frameCount > 0) {
+ /*
+ * Resizing an existing stack map frame table is really hard. Not
+ * only the table must be parsed to update the offets, but new
+ * frames may be needed for jump instructions that were inserted by
+ * this method. And updating the offsets or inserting frames can
+ * change the format of the following frames, in case of packed
+ * frames. In practice the whole table must be recomputed. For this
+ * the frames are marked as potentially invalid. This will cause the
+ * whole class to be reread and rewritten with the COMPUTE_FRAMES
+ * option (see the ClassWriter.toByteArray method). This is not very
+ * efficient but is much easier and requires much less code than any
+ * other method I can think of.
+ */
+ cw.invalidFrames = true;
}
// updates the exception handler block labels
Handler h = firstHandler;
diff --git a/src/asm/scala/tools/asm/Opcodes.java b/src/asm/scala/tools/asm/Opcodes.java
index 809e5ae590..24eaffa717 100644
--- a/src/asm/scala/tools/asm/Opcodes.java
+++ b/src/asm/scala/tools/asm/Opcodes.java
@@ -46,6 +46,7 @@ public interface Opcodes {
// ASM API versions
int ASM4 = 4 << 16 | 0 << 8 | 0;
+ int ASM5 = 5 << 16 | 0 << 8 | 0;
// versions
@@ -56,6 +57,7 @@ public interface Opcodes {
int V1_5 = 0 << 16 | 49;
int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51;
+ int V1_8 = 0 << 16 | 52;
// access flags
@@ -63,7 +65,7 @@ public interface Opcodes {
int ACC_PRIVATE = 0x0002; // class, field, method
int ACC_PROTECTED = 0x0004; // class, field, method
int ACC_STATIC = 0x0008; // field, method
- int ACC_FINAL = 0x0010; // class, field, method
+ int ACC_FINAL = 0x0010; // class, field, method, parameter
int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_VOLATILE = 0x0040; // field
@@ -74,9 +76,10 @@ public interface Opcodes {
int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method
- int ACC_SYNTHETIC = 0x1000; // class, field, method
+ int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
+ int ACC_MANDATED = 0x8000; // parameter
// ASM specific pseudo access flags
diff --git a/src/asm/scala/tools/asm/Type.java b/src/asm/scala/tools/asm/Type.java
index 7821a492e6..7887080dee 100644
--- a/src/asm/scala/tools/asm/Type.java
+++ b/src/asm/scala/tools/asm/Type.java
@@ -401,8 +401,8 @@ public class Type {
* @return the size of the arguments of the method (plus one for the
* implicit this argument), argSize, and the size of its return
* value, retSize, packed into a single int i =
- * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to
- * <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
+ * <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
+ * <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
*/
public static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
@@ -606,9 +606,10 @@ public class Type {
*
* @return the size of the arguments (plus one for the implicit this
* argument), argSize, and the size of the return value, retSize,
- * packed into a single int i = <tt>(argSize << 2) | retSize</tt>
- * (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
- * <tt>i & 0x03</tt>).
+ * packed into a single
+ * int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
+ * (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
+ * and retSize to <tt>i &amp; 0x03</tt>).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
diff --git a/src/asm/scala/tools/asm/TypePath.java b/src/asm/scala/tools/asm/TypePath.java
new file mode 100644
index 0000000000..d4c6f0d857
--- /dev/null
+++ b/src/asm/scala/tools/asm/TypePath.java
@@ -0,0 +1,193 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2013 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scala.tools.asm;
+
+/**
+ * The path to a type argument, wildcard bound, array element type, or static
+ * inner type within an enclosing type.
+ *
+ * @author Eric Bruneton
+ */
+public class TypePath {
+
+ /**
+ * A type path step that steps into the element type of an array type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int ARRAY_ELEMENT = 0;
+
+ /**
+ * A type path step that steps into the nested type of a class type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int INNER_TYPE = 1;
+
+ /**
+ * A type path step that steps into the bound of a wildcard type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int WILDCARD_BOUND = 2;
+
+ /**
+ * A type path step that steps into a type argument of a generic type. See
+ * {@link #getStep getStep}.
+ */
+ public final static int TYPE_ARGUMENT = 3;
+
+ /**
+ * The byte array where the path is stored, in Java class file format.
+ */
+ byte[] b;
+
+ /**
+ * The offset of the first byte of the type path in 'b'.
+ */
+ int offset;
+
+ /**
+ * Creates a new type path.
+ *
+ * @param b
+ * the byte array containing the type path in Java class file
+ * format.
+ * @param offset
+ * the offset of the first byte of the type path in 'b'.
+ */
+ TypePath(byte[] b, int offset) {
+ this.b = b;
+ this.offset = offset;
+ }
+
+ /**
+ * Returns the length of this path.
+ *
+ * @return the length of this path.
+ */
+ public int getLength() {
+ return b[offset];
+ }
+
+ /**
+ * Returns the value of the given step of this path.
+ *
+ * @param index
+ * an index between 0 and {@link #getLength()}, exclusive.
+ * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE
+ * INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or
+ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
+ */
+ public int getStep(int index) {
+ return b[offset + 2 * index + 1];
+ }
+
+ /**
+ * Returns the index of the type argument that the given step is stepping
+ * into. This method should only be used for steps whose value is
+ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
+ *
+ * @param index
+ * an index between 0 and {@link #getLength()}, exclusive.
+ * @return the index of the type argument that the given step is stepping
+ * into.
+ */
+ public int getStepArgument(int index) {
+ return b[offset + 2 * index + 2];
+ }
+
+ /**
+ * Converts a type path in string form, in the format used by
+ * {@link #toString()}, into a TypePath object.
+ *
+ * @param typePath
+ * a type path in string form, in the format used by
+ * {@link #toString()}. May be null or empty.
+ * @return the corresponding TypePath object, or null if the path is empty.
+ */
+ public static TypePath fromString(final String typePath) {
+ if (typePath == null || typePath.length() == 0) {
+ return null;
+ }
+ int n = typePath.length();
+ ByteVector out = new ByteVector(n);
+ out.putByte(0);
+ for (int i = 0; i < n;) {
+ char c = typePath.charAt(i++);
+ if (c == '[') {
+ out.put11(ARRAY_ELEMENT, 0);
+ } else if (c == '.') {
+ out.put11(INNER_TYPE, 0);
+ } else if (c == '*') {
+ out.put11(WILDCARD_BOUND, 0);
+ } else if (c >= '0' && c <= '9') {
+ int typeArg = c - '0';
+ while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
+ typeArg = typeArg * 10 + c - '0';
+ i += 1;
+ }
+ out.put11(TYPE_ARGUMENT, typeArg);
+ }
+ }
+ out.data[0] = (byte) (out.length / 2);
+ return new TypePath(out.data, 0);
+ }
+
+ /**
+ * Returns a string representation of this type path. {@link #ARRAY_ELEMENT
+ * ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE
+ * INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps
+ * with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type
+ * argument index in decimal form.
+ */
+ @Override
+ public String toString() {
+ int length = getLength();
+ StringBuilder result = new StringBuilder(length * 2);
+ for (int i = 0; i < length; ++i) {
+ switch (getStep(i)) {
+ case ARRAY_ELEMENT:
+ result.append('[');
+ break;
+ case INNER_TYPE:
+ result.append('.');
+ break;
+ case WILDCARD_BOUND:
+ result.append('*');
+ break;
+ case TYPE_ARGUMENT:
+ result.append(getStepArgument(i));
+ break;
+ default:
+ result.append('_');
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/src/asm/scala/tools/asm/TypeReference.java b/src/asm/scala/tools/asm/TypeReference.java
new file mode 100644
index 0000000000..118b0f6529
--- /dev/null
+++ b/src/asm/scala/tools/asm/TypeReference.java
@@ -0,0 +1,452 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2013 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scala.tools.asm;
+
+/**
+ * A reference to a type appearing in a class, field or method declaration, or
+ * on an instruction. Such a reference designates the part of the class where
+ * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
+ * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
+ * declaration, etc).
+ *
+ * @author Eric Bruneton
+ */
+public class TypeReference {
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * class. See {@link #getSort getSort}.
+ */
+ public final static int CLASS_TYPE_PARAMETER = 0x00;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * method. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_TYPE_PARAMETER = 0x01;
+
+ /**
+ * The sort of type references that target the super class of a class or one
+ * of the interfaces it implements. See {@link #getSort getSort}.
+ */
+ public final static int CLASS_EXTENDS = 0x10;
+
+ /**
+ * The sort of type references that target a bound of a type parameter of a
+ * generic class. See {@link #getSort getSort}.
+ */
+ public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
+
+ /**
+ * The sort of type references that target a bound of a type parameter of a
+ * generic method. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
+
+ /**
+ * The sort of type references that target the type of a field. See
+ * {@link #getSort getSort}.
+ */
+ public final static int FIELD = 0x13;
+
+ /**
+ * The sort of type references that target the return type of a method. See
+ * {@link #getSort getSort}.
+ */
+ public final static int METHOD_RETURN = 0x14;
+
+ /**
+ * The sort of type references that target the receiver type of a method.
+ * See {@link #getSort getSort}.
+ */
+ public final static int METHOD_RECEIVER = 0x15;
+
+ /**
+ * The sort of type references that target the type of a formal parameter of
+ * a method. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_FORMAL_PARAMETER = 0x16;
+
+ /**
+ * The sort of type references that target the type of an exception declared
+ * in the throws clause of a method. See {@link #getSort getSort}.
+ */
+ public final static int THROWS = 0x17;
+
+ /**
+ * The sort of type references that target the type of a local variable in a
+ * method. See {@link #getSort getSort}.
+ */
+ public final static int LOCAL_VARIABLE = 0x40;
+
+ /**
+ * The sort of type references that target the type of a resource variable
+ * in a method. See {@link #getSort getSort}.
+ */
+ public final static int RESOURCE_VARIABLE = 0x41;
+
+ /**
+ * The sort of type references that target the type of the exception of a
+ * 'catch' clause in a method. See {@link #getSort getSort}.
+ */
+ public final static int EXCEPTION_PARAMETER = 0x42;
+
+ /**
+ * The sort of type references that target the type declared in an
+ * 'instanceof' instruction. See {@link #getSort getSort}.
+ */
+ public final static int INSTANCEOF = 0x43;
+
+ /**
+ * The sort of type references that target the type of the object created by
+ * a 'new' instruction. See {@link #getSort getSort}.
+ */
+ public final static int NEW = 0x44;
+
+ /**
+ * The sort of type references that target the receiver type of a
+ * constructor reference. See {@link #getSort getSort}.
+ */
+ public final static int CONSTRUCTOR_REFERENCE = 0x45;
+
+ /**
+ * The sort of type references that target the receiver type of a method
+ * reference. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_REFERENCE = 0x46;
+
+ /**
+ * The sort of type references that target the type declared in an explicit
+ * or implicit cast instruction. See {@link #getSort getSort}.
+ */
+ public final static int CAST = 0x47;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * constructor in a constructor call. See {@link #getSort getSort}.
+ */
+ public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * method in a method call. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * constructor in a constructor reference. See {@link #getSort getSort}.
+ */
+ public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
+
+ /**
+ * The sort of type references that target a type parameter of a generic
+ * method in a method reference. See {@link #getSort getSort}.
+ */
+ public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
+
+ /**
+ * The type reference value in Java class file format.
+ */
+ private int value;
+
+ /**
+ * Creates a new TypeReference.
+ *
+ * @param typeRef
+ * the int encoded value of the type reference, as received in a
+ * visit method related to type annotations, like
+ * visitTypeAnnotation.
+ */
+ public TypeReference(int typeRef) {
+ this.value = typeRef;
+ }
+
+ /**
+ * Returns a type reference of the given sort.
+ *
+ * @param sort
+ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
+ * {@link #METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
+ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
+ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
+ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
+ * {@link #METHOD_REFERENCE METHOD_REFERENCE}.
+ * @return a type reference of the given sort.
+ */
+ public static TypeReference newTypeReference(int sort) {
+ return new TypeReference(sort << 24);
+ }
+
+ /**
+ * Returns a reference to a type parameter of a generic class or method.
+ *
+ * @param sort
+ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
+ * @param paramIndex
+ * the type parameter index.
+ * @return a reference to the given generic class or method type parameter.
+ */
+ public static TypeReference newTypeParameterReference(int sort,
+ int paramIndex) {
+ return new TypeReference((sort << 24) | (paramIndex << 16));
+ }
+
+ /**
+ * Returns a reference to a type parameter bound of a generic class or
+ * method.
+ *
+ * @param sort
+ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
+ * @param paramIndex
+ * the type parameter index.
+ * @param boundIndex
+ * the type bound index within the above type parameters.
+ * @return a reference to the given generic class or method type parameter
+ * bound.
+ */
+ public static TypeReference newTypeParameterBoundReference(int sort,
+ int paramIndex, int boundIndex) {
+ return new TypeReference((sort << 24) | (paramIndex << 16)
+ | (boundIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the super class or to an interface of the
+ * 'implements' clause of a class.
+ *
+ * @param itfIndex
+ * the index of an interface in the 'implements' clause of a
+ * class, or -1 to reference the super class of the class.
+ * @return a reference to the given super type of a class.
+ */
+ public static TypeReference newSuperTypeReference(int itfIndex) {
+ itfIndex &= 0xFFFF;
+ return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of a formal parameter of a method.
+ *
+ * @param paramIndex
+ * the formal parameter index.
+ *
+ * @return a reference to the type of the given method formal parameter.
+ */
+ public static TypeReference newFormalParameterReference(int paramIndex) {
+ return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
+ | (paramIndex << 16));
+ }
+
+ /**
+ * Returns a reference to the type of an exception, in a 'throws' clause of
+ * a method.
+ *
+ * @param exceptionIndex
+ * the index of an exception in a 'throws' clause of a method.
+ *
+ * @return a reference to the type of the given exception.
+ */
+ public static TypeReference newExceptionReference(int exceptionIndex) {
+ return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of the exception declared in a 'catch'
+ * clause of a method.
+ *
+ * @param tryCatchBlockIndex
+ * the index of a try catch block (using the order in which they
+ * are visited with visitTryCatchBlock).
+ *
+ * @return a reference to the type of the given exception.
+ */
+ public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
+ return new TypeReference((EXCEPTION_PARAMETER << 24)
+ | (tryCatchBlockIndex << 8));
+ }
+
+ /**
+ * Returns a reference to the type of a type argument in a constructor or
+ * method call or reference.
+ *
+ * @param sort
+ * {@link #CAST CAST},
+ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}.
+ * @param argIndex
+ * the type argument index.
+ *
+ * @return a reference to the type of the given type argument.
+ */
+ public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
+ return new TypeReference((sort << 24) | argIndex);
+ }
+
+ /**
+ * Returns the sort of this type reference.
+ *
+ * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
+ * {@link #CLASS_EXTENDS CLASS_EXTENDS},
+ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
+ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
+ * {@link #METHOD_RECEIVER METHOD_RECEIVER},
+ * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
+ * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
+ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
+ * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
+ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
+ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
+ * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
+ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT
+ * METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT
+ * METHOD_REFERENCE_TYPE_ARGUMENT}.
+ */
+ public int getSort() {
+ return value >>> 24;
+ }
+
+ /**
+ * Returns the index of the type parameter referenced by this type
+ * reference. This method must only be used for type references whose sort
+ * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
+ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
+ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
+ *
+ * @return a type parameter index.
+ */
+ public int getTypeParameterIndex() {
+ return (value & 0x00FF0000) >> 16;
+ }
+
+ /**
+ * Returns the index of the type parameter bound, within the type parameter
+ * {@link #getTypeParameterIndex}, referenced by this type reference. This
+ * method must only be used for type references whose sort is
+ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
+ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
+ *
+ * @return a type parameter bound index.
+ */
+ public int getTypeParameterBoundIndex() {
+ return (value & 0x0000FF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the "super type" of a class that is referenced by
+ * this type reference. This method must only be used for type references
+ * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
+ *
+ * @return the index of an interface in the 'implements' clause of a class,
+ * or -1 if this type reference references the type of the super
+ * class.
+ */
+ public int getSuperTypeIndex() {
+ return (short) ((value & 0x00FFFF00) >> 8);
+ }
+
+ /**
+ * Returns the index of the formal parameter whose type is referenced by
+ * this type reference. This method must only be used for type references
+ * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
+ *
+ * @return a formal parameter index.
+ */
+ public int getFormalParameterIndex() {
+ return (value & 0x00FF0000) >> 16;
+ }
+
+ /**
+ * Returns the index of the exception, in a 'throws' clause of a method,
+ * whose type is referenced by this type reference. This method must only be
+ * used for type references whose sort is {@link #THROWS THROWS}.
+ *
+ * @return the index of an exception in the 'throws' clause of a method.
+ */
+ public int getExceptionIndex() {
+ return (value & 0x00FFFF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the try catch block (using the order in which they
+ * are visited with visitTryCatchBlock), whose 'catch' type is referenced by
+ * this type reference. This method must only be used for type references
+ * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
+ *
+ * @return the index of an exception in the 'throws' clause of a method.
+ */
+ public int getTryCatchBlockIndex() {
+ return (value & 0x00FFFF00) >> 8;
+ }
+
+ /**
+ * Returns the index of the type argument referenced by this type reference.
+ * This method must only be used for type references whose sort is
+ * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
+ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
+ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
+ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
+ *
+ * @return a type parameter index.
+ */
+ public int getTypeArgumentIndex() {
+ return value & 0xFF;
+ }
+
+ /**
+ * Returns the int encoded value of this type reference, suitable for use in
+ * visit methods related to type annotations, like visitTypeAnnotation.
+ *
+ * @return the int encoded value of this type reference.
+ */
+ public int getValue() {
+ return value;
+ }
+}
diff --git a/src/asm/scala/tools/asm/signature/SignatureVisitor.java b/src/asm/scala/tools/asm/signature/SignatureVisitor.java
index f38f81f53b..1e16bd3f7c 100644
--- a/src/asm/scala/tools/asm/signature/SignatureVisitor.java
+++ b/src/asm/scala/tools/asm/signature/SignatureVisitor.java
@@ -73,7 +73,7 @@ public abstract class SignatureVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -82,9 +82,12 @@ public abstract class SignatureVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public SignatureVisitor(final int api) {
+ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {
+ throw new IllegalArgumentException();
+ }
this.api = api;
}
diff --git a/src/asm/scala/tools/asm/signature/SignatureWriter.java b/src/asm/scala/tools/asm/signature/SignatureWriter.java
index ebf4fe07b4..65756eee51 100644
--- a/src/asm/scala/tools/asm/signature/SignatureWriter.java
+++ b/src/asm/scala/tools/asm/signature/SignatureWriter.java
@@ -66,7 +66,7 @@ public class SignatureWriter extends SignatureVisitor {
* Constructs a new {@link SignatureWriter} object.
*/
public SignatureWriter() {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
}
// ------------------------------------------------------------------------
diff --git a/src/asm/scala/tools/asm/tree/AbstractInsnNode.java b/src/asm/scala/tools/asm/tree/AbstractInsnNode.java
index 411eead3c7..2ce0c8b6ee 100644
--- a/src/asm/scala/tools/asm/tree/AbstractInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/AbstractInsnNode.java
@@ -29,6 +29,7 @@
*/
package scala.tools.asm.tree;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -128,6 +129,28 @@ public abstract class AbstractInsnNode {
protected int opcode;
/**
+ * The runtime visible type annotations of this instruction. This field is
+ * only used for real instructions (i.e. not for labels, frames, or line
+ * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
+ * May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this instruction. This field is
+ * only used for real instructions (i.e. not for labels, frames, or line
+ * number nodes). This list is a list of {@link TypeAnnotationNode} objects.
+ * May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* Previous instruction in the list to which this instruction belongs.
*/
AbstractInsnNode prev;
@@ -204,6 +227,29 @@ public abstract class AbstractInsnNode {
public abstract void accept(final MethodVisitor cv);
/**
+ * Makes the given visitor visit the annotations of this instruction.
+ *
+ * @param mv
+ * a method visitor.
+ */
+ protected final void acceptAnnotations(final MethodVisitor mv) {
+ int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
+ }
+
+ /**
* Returns a copy of this instruction.
*
* @param labels
@@ -245,4 +291,36 @@ public abstract class AbstractInsnNode {
}
return clones;
}
+
+ /**
+ * Clones the annotations of the given instruction into this instruction.
+ *
+ * @param insn
+ * the source instruction.
+ * @return this instruction.
+ */
+ protected final AbstractInsnNode cloneAnnotations(
+ final AbstractInsnNode insn) {
+ if (insn.visibleTypeAnnotations != null) {
+ this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
+ for (int i = 0; i < insn.visibleTypeAnnotations.size(); ++i) {
+ TypeAnnotationNode src = insn.visibleTypeAnnotations.get(i);
+ TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
+ src.typePath, src.desc);
+ src.accept(ann);
+ this.visibleTypeAnnotations.add(ann);
+ }
+ }
+ if (insn.invisibleTypeAnnotations != null) {
+ this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
+ for (int i = 0; i < insn.invisibleTypeAnnotations.size(); ++i) {
+ TypeAnnotationNode src = insn.invisibleTypeAnnotations.get(i);
+ TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
+ src.typePath, src.desc);
+ src.accept(ann);
+ this.invisibleTypeAnnotations.add(ann);
+ }
+ }
+ return this;
+ }
}
diff --git a/src/asm/scala/tools/asm/tree/AnnotationNode.java b/src/asm/scala/tools/asm/tree/AnnotationNode.java
index 1f4beef9f7..b8d5988066 100644
--- a/src/asm/scala/tools/asm/tree/AnnotationNode.java
+++ b/src/asm/scala/tools/asm/tree/AnnotationNode.java
@@ -67,9 +67,14 @@ public class AnnotationNode extends AnnotationVisitor {
*
* @param desc
* the class descriptor of the annotation class.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public AnnotationNode(final String desc) {
- this(Opcodes.ASM4, desc);
+ this(Opcodes.ASM5, desc);
+ if (getClass() != AnnotationNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -77,7 +82,7 @@ public class AnnotationNode extends AnnotationVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param desc
* the class descriptor of the annotation class.
*/
@@ -93,7 +98,7 @@ public class AnnotationNode extends AnnotationVisitor {
* where the visited values must be stored.
*/
AnnotationNode(final List<Object> values) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
this.values = values;
}
@@ -166,7 +171,8 @@ public class AnnotationNode extends AnnotationVisitor {
* versions of the ASM API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
// nothing to do
diff --git a/src/asm/scala/tools/asm/tree/ClassNode.java b/src/asm/scala/tools/asm/tree/ClassNode.java
index c3d999985a..304b4ec9f5 100644
--- a/src/asm/scala/tools/asm/tree/ClassNode.java
+++ b/src/asm/scala/tools/asm/tree/ClassNode.java
@@ -39,6 +39,7 @@ import scala.tools.asm.ClassVisitor;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A node that represents a class.
@@ -133,6 +134,24 @@ public class ClassNode extends ClassVisitor {
public List<AnnotationNode> invisibleAnnotations;
/**
+ * The runtime visible type annotations of this class. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this class. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* The non standard attributes of this class. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
@@ -168,9 +187,15 @@ public class ClassNode extends ClassVisitor {
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #ClassNode(int)}
* version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public ClassNode() {
- this(Opcodes.ASM4);
+ this(Opcodes.ASM5);
+ if (getClass() != ClassNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -178,7 +203,7 @@ public class ClassNode extends ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public ClassNode(final int api) {
super(api);
@@ -239,6 +264,24 @@ public class ClassNode extends ClassVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (visibleTypeAnnotations == null) {
+ visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ visibleTypeAnnotations.add(an);
+ } else {
+ if (invisibleTypeAnnotations == null) {
+ invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
@@ -286,10 +329,26 @@ public class ClassNode extends ClassVisitor {
* API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
- // nothing to do
+ if (api == Opcodes.ASM4) {
+ if (visibleTypeAnnotations != null
+ && visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleTypeAnnotations != null
+ && invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ for (FieldNode f : fields) {
+ f.check(api);
+ }
+ for (MethodNode m : methods) {
+ m.check(api);
+ }
+ }
}
/**
@@ -323,6 +382,19 @@ public class ClassNode extends ClassVisitor {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, false));
}
+ n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
cv.visitAttribute(attrs.get(i));
diff --git a/src/asm/scala/tools/asm/tree/FieldInsnNode.java b/src/asm/scala/tools/asm/tree/FieldInsnNode.java
index 0c94f18adf..c027de109b 100644
--- a/src/asm/scala/tools/asm/tree/FieldInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/FieldInsnNode.java
@@ -97,12 +97,14 @@ public class FieldInsnNode extends AbstractInsnNode {
}
@Override
- public void accept(final MethodVisitor cv) {
- cv.visitFieldInsn(opcode, owner, name, desc);
+ public void accept(final MethodVisitor mv) {
+ mv.visitFieldInsn(opcode, owner, name, desc);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new FieldInsnNode(opcode, owner, name, desc);
+ return new FieldInsnNode(opcode, owner, name, desc)
+ .cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/FieldNode.java b/src/asm/scala/tools/asm/tree/FieldNode.java
index 61b614ec59..3fb14dac4f 100644
--- a/src/asm/scala/tools/asm/tree/FieldNode.java
+++ b/src/asm/scala/tools/asm/tree/FieldNode.java
@@ -37,6 +37,7 @@ import scala.tools.asm.Attribute;
import scala.tools.asm.ClassVisitor;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A node that represents a field.
@@ -92,6 +93,24 @@ public class FieldNode extends FieldVisitor {
public List<AnnotationNode> invisibleAnnotations;
/**
+ * The runtime visible type annotations of this field. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this field. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* The non standard attributes of this field. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
@@ -120,20 +139,24 @@ public class FieldNode extends FieldVisitor {
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public FieldNode(final int access, final String name, final String desc,
final String signature, final Object value) {
- this(Opcodes.ASM4, access, name, desc, signature, value);
+ this(Opcodes.ASM5, access, name, desc, signature, value);
+ if (getClass() != FieldNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this
- * constructor</i>. Instead, they must use the
- * {@link #FieldNode(int, int, String, String, String, Object)} version.
+ * constructor</i>.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param access
* the field's access flags (see
* {@link scala.tools.asm.Opcodes}). This parameter also
@@ -184,6 +207,24 @@ public class FieldNode extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (visibleTypeAnnotations == null) {
+ visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ visibleTypeAnnotations.add(an);
+ } else {
+ if (invisibleTypeAnnotations == null) {
+ invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
@@ -206,10 +247,20 @@ public class FieldNode extends FieldVisitor {
* API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
- // nothing to do
+ if (api == Opcodes.ASM4) {
+ if (visibleTypeAnnotations != null
+ && visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleTypeAnnotations != null
+ && invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
}
/**
@@ -234,6 +285,19 @@ public class FieldNode extends FieldVisitor {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, false));
}
+ n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
fv.visitAttribute(attrs.get(i));
diff --git a/src/asm/scala/tools/asm/tree/IincInsnNode.java b/src/asm/scala/tools/asm/tree/IincInsnNode.java
index f9adf2e38c..c37ac91c27 100644
--- a/src/asm/scala/tools/asm/tree/IincInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/IincInsnNode.java
@@ -73,10 +73,11 @@ public class IincInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitIincInsn(var, incr);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new IincInsnNode(var, incr);
+ return new IincInsnNode(var, incr).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/InsnList.java b/src/asm/scala/tools/asm/tree/InsnList.java
index b1e2d97c6f..e808712e78 100644
--- a/src/asm/scala/tools/asm/tree/InsnList.java
+++ b/src/asm/scala/tools/asm/tree/InsnList.java
@@ -100,7 +100,7 @@ public class InsnList {
* the index of the instruction that must be returned.
* @return the instruction whose index is given.
* @throws IndexOutOfBoundsException
- * if (index < 0 || index >= size()).
+ * if (index &lt; 0 || index &gt;= size()).
*/
public AbstractInsnNode get(final int index) {
if (index < 0 || index >= size) {
@@ -535,6 +535,8 @@ public class InsnList {
AbstractInsnNode prev;
+ AbstractInsnNode remove;
+
InsnListIterator(int index) {
if (index == size()) {
next = null;
@@ -556,12 +558,22 @@ public class InsnList {
AbstractInsnNode result = next;
prev = result;
next = result.next;
+ remove = result;
return result;
}
public void remove() {
- InsnList.this.remove(prev);
- prev = prev.prev;
+ if (remove != null) {
+ if (remove == next) {
+ next = next.next;
+ } else {
+ prev = prev.prev;
+ }
+ InsnList.this.remove(remove);
+ remove = null;
+ } else {
+ throw new IllegalStateException();
+ }
}
public boolean hasPrevious() {
@@ -572,6 +584,7 @@ public class InsnList {
AbstractInsnNode result = prev;
next = result;
prev = result.prev;
+ remove = result;
return result;
}
@@ -598,6 +611,7 @@ public class InsnList {
public void add(Object o) {
InsnList.this.insertBefore(next, (AbstractInsnNode) o);
prev = (AbstractInsnNode) o;
+ remove = null;
}
public void set(Object o) {
diff --git a/src/asm/scala/tools/asm/tree/InsnNode.java b/src/asm/scala/tools/asm/tree/InsnNode.java
index 4d5288cafa..f5313929ee 100644
--- a/src/asm/scala/tools/asm/tree/InsnNode.java
+++ b/src/asm/scala/tools/asm/tree/InsnNode.java
@@ -78,10 +78,11 @@ public class InsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitInsn(opcode);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new InsnNode(opcode);
+ return new InsnNode(opcode).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/IntInsnNode.java b/src/asm/scala/tools/asm/tree/IntInsnNode.java
index e0aeed4bc8..6bbe8d845c 100644
--- a/src/asm/scala/tools/asm/tree/IntInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/IntInsnNode.java
@@ -78,10 +78,11 @@ public class IntInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitIntInsn(opcode, operand);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new IntInsnNode(opcode, operand);
+ return new IntInsnNode(opcode, operand).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java b/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java
index 7ee84b875b..0f85e60291 100644
--- a/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/InvokeDynamicInsnNode.java
@@ -91,10 +91,12 @@ public class InvokeDynamicInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs);
+ return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)
+ .cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/JumpInsnNode.java b/src/asm/scala/tools/asm/tree/JumpInsnNode.java
index 81e1e09deb..8b8a769204 100644
--- a/src/asm/scala/tools/asm/tree/JumpInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/JumpInsnNode.java
@@ -86,10 +86,12 @@ public class JumpInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitJumpInsn(opcode, label.getLabel());
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new JumpInsnNode(opcode, clone(label, labels));
+ return new JumpInsnNode(opcode, clone(label, labels))
+ .cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/LdcInsnNode.java b/src/asm/scala/tools/asm/tree/LdcInsnNode.java
index 4e328f9b39..1cc850bb31 100644
--- a/src/asm/scala/tools/asm/tree/LdcInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/LdcInsnNode.java
@@ -69,10 +69,11 @@ public class LdcInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitLdcInsn(cst);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new LdcInsnNode(cst);
+ return new LdcInsnNode(cst).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java b/src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java
new file mode 100644
index 0000000000..d05b808171
--- /dev/null
+++ b/src/asm/scala/tools/asm/tree/LocalVariableAnnotationNode.java
@@ -0,0 +1,157 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scala.tools.asm.tree;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import scala.tools.asm.Label;
+import scala.tools.asm.MethodVisitor;
+import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
+
+/**
+ * A node that represents a type annotation on a local or resource variable.
+ *
+ * @author Eric Bruneton
+ */
+public class LocalVariableAnnotationNode extends TypeAnnotationNode {
+
+ /**
+ * The fist instructions corresponding to the continuous ranges that make
+ * the scope of this local variable (inclusive). Must not be <tt>null</tt>.
+ */
+ public List<LabelNode> start;
+
+ /**
+ * The last instructions corresponding to the continuous ranges that make
+ * the scope of this local variable (exclusive). This list must have the
+ * same size as the 'start' list. Must not be <tt>null</tt>.
+ */
+ public List<LabelNode> end;
+
+ /**
+ * The local variable's index in each range. This list must have the same
+ * size as the 'start' list. Must not be <tt>null</tt>.
+ */
+ public List<Integer> index;
+
+ /**
+ * Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must
+ * not use this constructor</i>. Instead, they must use the
+ * {@link #LocalVariableAnnotationNode(int, TypePath, LabelNode[], LabelNode[], int[], String)}
+ * version.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param start
+ * the fist instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (inclusive).
+ * @param end
+ * the last instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (exclusive). This
+ * array must have the same size as the 'start' array.
+ * @param index
+ * the local variable's index in each range. This array must have
+ * the same size as the 'start' array.
+ * @param desc
+ * the class descriptor of the annotation class.
+ */
+ public LocalVariableAnnotationNode(int typeRef, TypePath typePath,
+ LabelNode[] start, LabelNode[] end, int[] index, String desc) {
+ this(Opcodes.ASM5, typeRef, typePath, start, end, index, desc);
+ }
+
+ /**
+ * Constructs a new {@link LocalVariableAnnotationNode}.
+ *
+ * @param api
+ * the ASM API version implemented by this visitor. Must be one
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param start
+ * the fist instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (inclusive).
+ * @param end
+ * the last instructions corresponding to the continuous ranges
+ * that make the scope of this local variable (exclusive). This
+ * array must have the same size as the 'start' array.
+ * @param index
+ * the local variable's index in each range. This array must have
+ * the same size as the 'start' array.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ */
+ public LocalVariableAnnotationNode(int api, int typeRef, TypePath typePath,
+ LabelNode[] start, LabelNode[] end, int[] index, String desc) {
+ super(api, typeRef, typePath, desc);
+ this.start = new ArrayList<LabelNode>(start.length);
+ this.start.addAll(Arrays.asList(start));
+ this.end = new ArrayList<LabelNode>(end.length);
+ this.end.addAll(Arrays.asList(end));
+ this.index = new ArrayList<Integer>(index.length);
+ for (int i : index) {
+ this.index.add(i);
+ }
+ }
+
+ /**
+ * Makes the given visitor visit this type annotation.
+ *
+ * @param mv
+ * the visitor that must visit this annotation.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ */
+ public void accept(final MethodVisitor mv, boolean visible) {
+ Label[] start = new Label[this.start.size()];
+ Label[] end = new Label[this.end.size()];
+ int[] index = new int[this.index.size()];
+ for (int i = 0; i < start.length; ++i) {
+ start[i] = this.start.get(i).getLabel();
+ end[i] = this.end.get(i).getLabel();
+ index[i] = this.index.get(i);
+ }
+ accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
+ index, desc, true));
+ }
+}
diff --git a/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java b/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java
index d2479b4814..7db2f53ff4 100644
--- a/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/LookupSwitchInsnNode.java
@@ -105,6 +105,7 @@ public class LookupSwitchInsnNode extends AbstractInsnNode {
labels[i] = this.labels.get(i).getLabel();
}
mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels);
+ acceptAnnotations(mv);
}
@Override
@@ -112,6 +113,6 @@ public class LookupSwitchInsnNode extends AbstractInsnNode {
LookupSwitchInsnNode clone = new LookupSwitchInsnNode(clone(dflt,
labels), null, clone(this.labels, labels));
clone.keys.addAll(keys);
- return clone;
+ return clone.cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/MethodInsnNode.java b/src/asm/scala/tools/asm/tree/MethodInsnNode.java
index bf09f556d8..1ec46d473d 100644
--- a/src/asm/scala/tools/asm/tree/MethodInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/MethodInsnNode.java
@@ -32,6 +32,7 @@ package scala.tools.asm.tree;
import java.util.Map;
import scala.tools.asm.MethodVisitor;
+import scala.tools.asm.Opcodes;
/**
* A node that represents a method instruction. A method instruction is an
@@ -58,6 +59,11 @@ public class MethodInsnNode extends AbstractInsnNode {
public String desc;
/**
+ * If the method's owner class if an interface.
+ */
+ public boolean itf;
+
+ /**
* Constructs a new {@link MethodInsnNode}.
*
* @param opcode
@@ -73,12 +79,37 @@ public class MethodInsnNode extends AbstractInsnNode {
* @param desc
* the method's descriptor (see {@link scala.tools.asm.Type}).
*/
+ @Deprecated
public MethodInsnNode(final int opcode, final String owner,
final String name, final String desc) {
+ this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ /**
+ * Constructs a new {@link MethodInsnNode}.
+ *
+ * @param opcode
+ * the opcode of the type instruction to be constructed. This
+ * opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
+ * INVOKEINTERFACE.
+ * @param owner
+ * the internal name of the method's owner class (see
+ * {@link scala.tools.asm.Type#getInternalName()
+ * getInternalName}).
+ * @param name
+ * the method's name.
+ * @param desc
+ * the method's descriptor (see {@link scala.tools.asm.Type}).
+ * @param itf
+ * if the method's owner class is an interface.
+ */
+ public MethodInsnNode(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
super(opcode);
this.owner = owner;
this.name = name;
this.desc = desc;
+ this.itf = itf;
}
/**
@@ -99,11 +130,11 @@ public class MethodInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
- mv.visitMethodInsn(opcode, owner, name, desc);
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new MethodInsnNode(opcode, owner, name, desc);
+ return new MethodInsnNode(opcode, owner, name, desc, itf);
}
}
diff --git a/src/asm/scala/tools/asm/tree/MethodNode.java b/src/asm/scala/tools/asm/tree/MethodNode.java
index a161600edb..3dec50e02c 100644
--- a/src/asm/scala/tools/asm/tree/MethodNode.java
+++ b/src/asm/scala/tools/asm/tree/MethodNode.java
@@ -41,6 +41,7 @@ import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
/**
* A node that represents a method.
@@ -78,6 +79,11 @@ public class MethodNode extends MethodVisitor {
public List<String> exceptions;
/**
+ * The method parameter info (access flags and name)
+ */
+ public List<ParameterNode> parameters;
+
+ /**
* The runtime visible annotations of this method. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
@@ -96,6 +102,24 @@ public class MethodNode extends MethodVisitor {
public List<AnnotationNode> invisibleAnnotations;
/**
+ * The runtime visible type annotations of this method. This list is a list
+ * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations of this method. This list is a
+ * list of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* The non standard attributes of this method. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
@@ -167,6 +191,22 @@ public class MethodNode extends MethodVisitor {
public List<LocalVariableNode> localVariables;
/**
+ * The visible local variable annotations of this method. This list is a
+ * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
+ *
+ * @associates scala.tools.asm.tree.LocalVariableAnnotationNode
+ */
+ public List<LocalVariableAnnotationNode> visibleLocalVariableAnnotations;
+
+ /**
+ * The invisible local variable annotations of this method. This list is a
+ * list of {@link LocalVariableAnnotationNode} objects. May be <tt>null</tt>
+ *
+ * @associates scala.tools.asm.tree.LocalVariableAnnotationNode
+ */
+ public List<LocalVariableAnnotationNode> invisibleLocalVariableAnnotations;
+
+ /**
* If the accept method has been called on this object.
*/
private boolean visited;
@@ -175,9 +215,15 @@ public class MethodNode extends MethodVisitor {
* Constructs an uninitialized {@link MethodNode}. <i>Subclasses must not
* use this constructor</i>. Instead, they must use the
* {@link #MethodNode(int)} version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public MethodNode() {
- this(Opcodes.ASM4);
+ this(Opcodes.ASM5);
+ if (getClass() != MethodNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -185,7 +231,7 @@ public class MethodNode extends MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
public MethodNode(final int api) {
super(api);
@@ -211,10 +257,15 @@ public class MethodNode extends MethodVisitor {
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public MethodNode(final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
- this(Opcodes.ASM4, access, name, desc, signature, exceptions);
+ this(Opcodes.ASM5, access, name, desc, signature, exceptions);
+ if (getClass() != MethodNode.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -222,7 +273,7 @@ public class MethodNode extends MethodVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
@@ -263,6 +314,15 @@ public class MethodNode extends MethodVisitor {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(String name, int access) {
+ if (parameters == null) {
+ parameters = new ArrayList<ParameterNode>(5);
+ }
+ parameters.add(new ParameterNode(name, access));
+ }
+
+ @Override
+ @SuppressWarnings("serial")
public AnnotationVisitor visitAnnotationDefault() {
return new AnnotationNode(new ArrayList<Object>(0) {
@Override
@@ -292,6 +352,24 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (visibleTypeAnnotations == null) {
+ visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ visibleTypeAnnotations.add(an);
+ } else {
+ if (invisibleTypeAnnotations == null) {
+ invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
+ }
+ invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public AnnotationVisitor visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
@@ -365,13 +443,28 @@ public class MethodNode extends MethodVisitor {
instructions.add(new FieldInsnNode(opcode, owner, name, desc));
}
+ @Deprecated
@Override
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
instructions.add(new MethodInsnNode(opcode, owner, name, desc));
}
@Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
+ }
+
+ @Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
instructions.add(new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs));
@@ -417,6 +510,33 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ // Finds the last real instruction, i.e. the instruction targeted by
+ // this annotation.
+ AbstractInsnNode insn = instructions.getLast();
+ while (insn.getOpcode() == -1) {
+ insn = insn.getPrevious();
+ }
+ // Adds the annotation to this instruction.
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (insn.visibleTypeAnnotations == null) {
+ insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ insn.visibleTypeAnnotations.add(an);
+ } else {
+ if (insn.invisibleTypeAnnotations == null) {
+ insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ insn.invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
tryCatchBlocks.add(new TryCatchBlockNode(getLabelNode(start),
@@ -424,6 +544,27 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ TryCatchBlockNode tcb = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
+ TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
+ if (visible) {
+ if (tcb.visibleTypeAnnotations == null) {
+ tcb.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ tcb.visibleTypeAnnotations.add(an);
+ } else {
+ if (tcb.invisibleTypeAnnotations == null) {
+ tcb.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(
+ 1);
+ }
+ tcb.invisibleTypeAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -432,6 +573,29 @@ public class MethodNode extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ LocalVariableAnnotationNode an = new LocalVariableAnnotationNode(
+ typeRef, typePath, getLabelNodes(start), getLabelNodes(end),
+ index, desc);
+ if (visible) {
+ if (visibleLocalVariableAnnotations == null) {
+ visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
+ 1);
+ }
+ visibleLocalVariableAnnotations.add(an);
+ } else {
+ if (invisibleLocalVariableAnnotations == null) {
+ invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(
+ 1);
+ }
+ invisibleLocalVariableAnnotations.add(an);
+ }
+ return an;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
instructions.add(new LineNumberNode(line, getLabelNode(start)));
}
@@ -494,10 +658,57 @@ public class MethodNode extends MethodVisitor {
* versions of the ASM API than the given version.
*
* @param api
- * an ASM API version. Must be one of {@link Opcodes#ASM4}.
+ * an ASM API version. Must be one of {@link Opcodes#ASM4} or
+ * {@link Opcodes#ASM5}.
*/
public void check(final int api) {
- // nothing to do
+ if (api == Opcodes.ASM4) {
+ if (visibleTypeAnnotations != null
+ && visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleTypeAnnotations != null
+ && invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ int n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
+ for (int i = 0; i < n; ++i) {
+ TryCatchBlockNode tcb = tryCatchBlocks.get(i);
+ if (tcb.visibleTypeAnnotations != null
+ && tcb.visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (tcb.invisibleTypeAnnotations != null
+ && tcb.invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
+ for (int i = 0; i < instructions.size(); ++i) {
+ AbstractInsnNode insn = instructions.get(i);
+ if (insn.visibleTypeAnnotations != null
+ && insn.visibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (insn.invisibleTypeAnnotations != null
+ && insn.invisibleTypeAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (insn instanceof MethodInsnNode) {
+ boolean itf = ((MethodInsnNode) insn).itf;
+ if (itf != (insn.opcode == Opcodes.INVOKEINTERFACE)) {
+ throw new RuntimeException();
+ }
+ }
+ }
+ if (visibleLocalVariableAnnotations != null
+ && visibleLocalVariableAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ if (invisibleLocalVariableAnnotations != null
+ && invisibleLocalVariableAnnotations.size() > 0) {
+ throw new RuntimeException();
+ }
+ }
}
/**
@@ -523,8 +734,14 @@ public class MethodNode extends MethodVisitor {
* a method visitor.
*/
public void accept(final MethodVisitor mv) {
- // visits the method attributes
+ // visits the method parameters
int i, j, n;
+ n = parameters == null ? 0 : parameters.size();
+ for (i = 0; i < n; i++) {
+ ParameterNode parameter = parameters.get(i);
+ mv.visitParameter(parameter.name, parameter.access);
+ }
+ // visits the method attributes
if (annotationDefault != null) {
AnnotationVisitor av = mv.visitAnnotationDefault();
AnnotationNode.accept(av, null, annotationDefault);
@@ -542,6 +759,19 @@ public class MethodNode extends MethodVisitor {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(mv.visitAnnotation(an.desc, false));
}
+ n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(mv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
+ false));
+ }
n = visibleParameterAnnotations == null ? 0
: visibleParameterAnnotations.length;
for (i = 0; i < n; ++i) {
@@ -579,6 +809,7 @@ public class MethodNode extends MethodVisitor {
// visits try catch blocks
n = tryCatchBlocks == null ? 0 : tryCatchBlocks.size();
for (i = 0; i < n; ++i) {
+ tryCatchBlocks.get(i).updateIndex(i);
tryCatchBlocks.get(i).accept(mv);
}
// visits instructions
@@ -588,6 +819,17 @@ public class MethodNode extends MethodVisitor {
for (i = 0; i < n; ++i) {
localVariables.get(i).accept(mv);
}
+ // visits local variable annotations
+ n = visibleLocalVariableAnnotations == null ? 0
+ : visibleLocalVariableAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ visibleLocalVariableAnnotations.get(i).accept(mv, true);
+ }
+ n = invisibleLocalVariableAnnotations == null ? 0
+ : invisibleLocalVariableAnnotations.size();
+ for (i = 0; i < n; ++i) {
+ invisibleLocalVariableAnnotations.get(i).accept(mv, false);
+ }
// visits maxs
mv.visitMaxs(maxStack, maxLocals);
visited = true;
diff --git a/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java b/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java
index fe5e8832b3..a8339a20b5 100644
--- a/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/MultiANewArrayInsnNode.java
@@ -73,11 +73,12 @@ public class MultiANewArrayInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitMultiANewArrayInsn(desc, dims);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new MultiANewArrayInsnNode(desc, dims);
+ return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/ParameterNode.java b/src/asm/scala/tools/asm/tree/ParameterNode.java
new file mode 100644
index 0000000000..a3e55d5629
--- /dev/null
+++ b/src/asm/scala/tools/asm/tree/ParameterNode.java
@@ -0,0 +1,76 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package scala.tools.asm.tree;
+
+import scala.tools.asm.MethodVisitor;
+
+/**
+ * A node that represents a parameter access and name.
+ *
+ * @author Remi Forax
+ */
+public class ParameterNode {
+ /**
+ * The parameter's name.
+ */
+ public String name;
+
+ /**
+ * The parameter's access flags (see {@link scala.tools.asm.Opcodes}).
+ * Valid values are <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and
+ * <tt>ACC_MANDATED</tt>.
+ */
+ public int access;
+
+ /**
+ * Constructs a new {@link ParameterNode}.
+ *
+ * @param access
+ * The parameter's access flags. Valid values are
+ * <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> or/and
+ * <tt>ACC_MANDATED</tt> (see {@link scala.tools.asm.Opcodes}).
+ * @param name
+ * the parameter's name.
+ */
+ public ParameterNode(final String name, final int access) {
+ this.name = name;
+ this.access = access;
+ }
+
+ /**
+ * Makes the given visitor visit this parameter declaration.
+ *
+ * @param mv
+ * a method visitor.
+ */
+ public void accept(final MethodVisitor mv) {
+ mv.visitParameter(name, access);
+ }
+}
diff --git a/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java b/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java
index 9b3c2a3437..fb17b9e2e9 100644
--- a/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/TableSwitchInsnNode.java
@@ -103,11 +103,12 @@ public class TableSwitchInsnNode extends AbstractInsnNode {
labels[i] = this.labels.get(i).getLabel();
}
mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone(
- this.labels, labels));
+ this.labels, labels)).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java b/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java
index ab4fa97c34..c639b9aa8b 100644
--- a/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java
+++ b/src/asm/scala/tools/asm/tree/TryCatchBlockNode.java
@@ -29,6 +29,8 @@
*/
package scala.tools.asm.tree;
+import java.util.List;
+
import scala.tools.asm.MethodVisitor;
/**
@@ -60,6 +62,26 @@ public class TryCatchBlockNode {
public String type;
/**
+ * The runtime visible type annotations on the exception handler type. This
+ * list is a list of {@link TypeAnnotationNode} objects. May be
+ * <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label visible
+ */
+ public List<TypeAnnotationNode> visibleTypeAnnotations;
+
+ /**
+ * The runtime invisible type annotations on the exception handler type.
+ * This list is a list of {@link TypeAnnotationNode} objects. May be
+ * <tt>null</tt>.
+ *
+ * @associates scala.tools.asm.tree.TypeAnnotationNode
+ * @label invisible
+ */
+ public List<TypeAnnotationNode> invisibleTypeAnnotations;
+
+ /**
* Constructs a new {@link TryCatchBlockNode}.
*
* @param start
@@ -82,6 +104,29 @@ public class TryCatchBlockNode {
}
/**
+ * Updates the index of this try catch block in the method's list of try
+ * catch block nodes. This index maybe stored in the 'target' field of the
+ * type annotations of this block.
+ *
+ * @param index
+ * the new index of this try catch block in the method's list of
+ * try catch block nodes.
+ */
+ public void updateIndex(final int index) {
+ int newTypeRef = 0x42000000 | (index << 8);
+ if (visibleTypeAnnotations != null) {
+ for (TypeAnnotationNode tan : visibleTypeAnnotations) {
+ tan.typeRef = newTypeRef;
+ }
+ }
+ if (invisibleTypeAnnotations != null) {
+ for (TypeAnnotationNode tan : invisibleTypeAnnotations) {
+ tan.typeRef = newTypeRef;
+ }
+ }
+ }
+
+ /**
* Makes the given visitor visit this try catch block.
*
* @param mv
@@ -90,5 +135,19 @@ public class TryCatchBlockNode {
public void accept(final MethodVisitor mv) {
mv.visitTryCatchBlock(start.getLabel(), end.getLabel(),
handler == null ? null : handler.getLabel(), type);
+ int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = visibleTypeAnnotations.get(i);
+ an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
+ an.desc, true));
+ }
+ n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
+ .size();
+ for (int i = 0; i < n; ++i) {
+ TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
+ an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
+ an.desc, false));
+ }
}
}
diff --git a/src/asm/scala/tools/asm/tree/TypeAnnotationNode.java b/src/asm/scala/tools/asm/tree/TypeAnnotationNode.java
new file mode 100644
index 0000000000..73b29624f7
--- /dev/null
+++ b/src/asm/scala/tools/asm/tree/TypeAnnotationNode.java
@@ -0,0 +1,100 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package scala.tools.asm.tree;
+
+import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
+
+/**
+ * A node that represents a type annotationn.
+ *
+ * @author Eric Bruneton
+ */
+public class TypeAnnotationNode extends AnnotationNode {
+
+ /**
+ * A reference to the annotated type. See {@link TypeReference}.
+ */
+ public int typeRef;
+
+ /**
+ * The path to the annotated type argument, wildcard bound, array element
+ * type, or static outer type within the referenced type. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ */
+ public TypePath typePath;
+
+ /**
+ * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
+ * constructor</i>. Instead, they must use the
+ * {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
+ */
+ public TypeAnnotationNode(final int typeRef, final TypePath typePath,
+ final String desc) {
+ this(Opcodes.ASM5, typeRef, typePath, desc);
+ if (getClass() != TypeAnnotationNode.class) {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Constructs a new {@link AnnotationNode}.
+ *
+ * @param api
+ * the ASM API version implemented by this visitor. Must be one
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ */
+ public TypeAnnotationNode(final int api, final int typeRef,
+ final TypePath typePath, final String desc) {
+ super(api, desc);
+ this.typeRef = typeRef;
+ this.typePath = typePath;
+ }
+}
diff --git a/src/asm/scala/tools/asm/tree/TypeInsnNode.java b/src/asm/scala/tools/asm/tree/TypeInsnNode.java
index 3210dd60e6..401400c3cb 100644
--- a/src/asm/scala/tools/asm/tree/TypeInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/TypeInsnNode.java
@@ -81,10 +81,11 @@ public class TypeInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitTypeInsn(opcode, desc);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new TypeInsnNode(opcode, desc);
+ return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/VarInsnNode.java b/src/asm/scala/tools/asm/tree/VarInsnNode.java
index 5dd9ef6726..685e4fce2c 100644
--- a/src/asm/scala/tools/asm/tree/VarInsnNode.java
+++ b/src/asm/scala/tools/asm/tree/VarInsnNode.java
@@ -84,10 +84,11 @@ public class VarInsnNode extends AbstractInsnNode {
@Override
public void accept(final MethodVisitor mv) {
mv.visitVarInsn(opcode, var);
+ acceptAnnotations(mv);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
- return new VarInsnNode(opcode, var);
+ return new VarInsnNode(opcode, var).cloneAnnotations(this);
}
}
diff --git a/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java b/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java
index 5e3f51f21a..52b2a11d6f 100644
--- a/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java
+++ b/src/asm/scala/tools/asm/tree/analysis/AnalyzerException.java
@@ -37,6 +37,7 @@ import scala.tools.asm.tree.AbstractInsnNode;
* @author Bing Ran
* @author Eric Bruneton
*/
+@SuppressWarnings("serial")
public class AnalyzerException extends Exception {
public final AbstractInsnNode node;
diff --git a/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java b/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java
index 8d6653c1c5..7d0b7b0694 100644
--- a/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java
+++ b/src/asm/scala/tools/asm/tree/analysis/BasicInterpreter.java
@@ -53,7 +53,7 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements
Opcodes {
public BasicInterpreter() {
- super(ASM4);
+ super(ASM5);
}
protected BasicInterpreter(final int api) {
diff --git a/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java b/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java
index 71666edb74..b852f20acf 100644
--- a/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java
+++ b/src/asm/scala/tools/asm/tree/analysis/BasicVerifier.java
@@ -47,7 +47,7 @@ import scala.tools.asm.tree.MethodInsnNode;
public class BasicVerifier extends BasicInterpreter {
public BasicVerifier() {
- super(ASM4);
+ super(ASM5);
}
protected BasicVerifier(final int api) {
diff --git a/src/asm/scala/tools/asm/tree/analysis/Frame.java b/src/asm/scala/tools/asm/tree/analysis/Frame.java
index 0d92edc4d6..44a07ee27c 100644
--- a/src/asm/scala/tools/asm/tree/analysis/Frame.java
+++ b/src/asm/scala/tools/asm/tree/analysis/Frame.java
@@ -134,6 +134,15 @@ public class Frame<V extends Value> {
}
/**
+ * Returns the maximum stack size of this frame.
+ *
+ * @return the maximum stack size of this frame.
+ */
+ public int getMaxStackSize() {
+ return values.length - locals;
+ }
+
+ /**
* Returns the value of the given local variable.
*
* @param i
diff --git a/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java b/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java
index eaecd057ea..a345981f36 100644
--- a/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java
+++ b/src/asm/scala/tools/asm/tree/analysis/SimpleVerifier.java
@@ -107,7 +107,7 @@ public class SimpleVerifier extends BasicVerifier {
public SimpleVerifier(final Type currentClass,
final Type currentSuperClass,
final List<Type> currentClassInterfaces, final boolean isInterface) {
- this(ASM4, currentClass, currentSuperClass, currentClassInterfaces,
+ this(ASM5, currentClass, currentSuperClass, currentClassInterfaces,
isInterface);
}
diff --git a/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java b/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java
index a68086c073..7d739d3df9 100644
--- a/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java
+++ b/src/asm/scala/tools/asm/tree/analysis/SourceInterpreter.java
@@ -50,7 +50,7 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements
Opcodes {
public SourceInterpreter() {
- super(ASM4);
+ super(ASM5);
}
protected SourceInterpreter(final int api) {
diff --git a/src/asm/scala/tools/asm/util/ASMifier.java b/src/asm/scala/tools/asm/util/ASMifier.java
index 7e6b223853..521e07541b 100644
--- a/src/asm/scala/tools/asm/util/ASMifier.java
+++ b/src/asm/scala/tools/asm/util/ASMifier.java
@@ -40,6 +40,7 @@ import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
/**
* A {@link Printer} that prints the ASM code to generate the classes if visits.
@@ -83,9 +84,15 @@ public class ASMifier extends Printer {
* Constructs a new {@link ASMifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #ASMifier(int, String, int)} version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public ASMifier() {
- this(Opcodes.ASM4, "cw", 0);
+ this(Opcodes.ASM5, "cw", 0);
+ if (getClass() != ASMifier.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -93,7 +100,7 @@ public class ASMifier extends Printer {
*
* @param api
* the ASM API version implemented by this class. Must be one of
- * {@link Opcodes#ASM4}.
+ * {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param name
* the name of the visitor variable in the produced code.
* @param id
@@ -170,7 +177,6 @@ public class ASMifier extends Printer {
}
text.add("import java.util.*;\n");
text.add("import scala.tools.asm.*;\n");
- text.add("import scala.tools.asm.attrs.*;\n");
text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
text.add("public static byte[] dump () throws Exception {\n\n");
text.add("ClassWriter cw = new ClassWriter(0);\n");
@@ -261,6 +267,12 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitClassTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitClassAttribute(final Attribute attr) {
visitAttribute(attr);
}
@@ -423,6 +435,12 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitFieldTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitFieldAttribute(final Attribute attr) {
visitAttribute(attr);
}
@@ -439,6 +457,16 @@ public class ASMifier extends Printer {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(String parameterName, int access) {
+ buf.setLength(0);
+ buf.append(name).append(".visitParameter(");
+ appendString(buf, parameterName);
+ buf.append(", ");
+ appendAccess(access);
+ text.add(buf.append(");\n").toString());
+ }
+
+ @Override
public ASMifier visitAnnotationDefault() {
buf.setLength(0);
buf.append("{\n").append("av0 = ").append(name)
@@ -457,6 +485,12 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitMethodTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public ASMifier visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
buf.setLength(0);
@@ -582,9 +616,30 @@ public class ASMifier extends Printer {
text.add(buf.toString());
}
+ @Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc,
+ opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ @Override
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ private void doVisitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
buf.setLength(0);
buf.append(this.name).append(".visitMethodInsn(")
.append(OPCODES[opcode]).append(", ");
@@ -593,6 +648,8 @@ public class ASMifier extends Printer {
appendConstant(name);
buf.append(", ");
appendConstant(desc);
+ buf.append(", ");
+ buf.append(itf ? "true" : "false");
buf.append(");\n");
text.add(buf.toString());
}
@@ -711,6 +768,13 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitInsnAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath,
+ desc, visible);
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
buf.setLength(0);
@@ -730,6 +794,13 @@ public class ASMifier extends Printer {
}
@Override
+ public ASMifier visitTryCatchAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation("visitTryCatchAnnotation", typeRef,
+ typePath, desc, visible);
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -749,6 +820,39 @@ public class ASMifier extends Printer {
}
@Override
+ public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
+ Label[] start, Label[] end, int[] index, String desc,
+ boolean visible) {
+ buf.setLength(0);
+ buf.append("{\n").append("av0 = ").append(name)
+ .append(".visitLocalVariableAnnotation(");
+ buf.append(typeRef);
+ buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
+ buf.append("new Label[] {");
+ for (int i = 0; i < start.length; ++i) {
+ buf.append(i == 0 ? " " : ", ");
+ appendLabel(start[i]);
+ }
+ buf.append(" }, new Label[] {");
+ for (int i = 0; i < end.length; ++i) {
+ buf.append(i == 0 ? " " : ", ");
+ appendLabel(end[i]);
+ }
+ buf.append(" }, new int[] {");
+ for (int i = 0; i < index.length; ++i) {
+ buf.append(i == 0 ? " " : ", ").append(index[i]);
+ }
+ buf.append(" }, ");
+ appendConstant(desc);
+ buf.append(", ").append(visible).append(");\n");
+ text.add(buf.toString());
+ ASMifier a = createASMifier("av", 0);
+ text.add(a.getText());
+ text.add("}\n");
+ return a;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
buf.setLength(0);
buf.append(name).append(".visitLineNumber(").append(line).append(", ");
@@ -789,6 +893,28 @@ public class ASMifier extends Printer {
return a;
}
+ public ASMifier visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath,
+ desc, visible);
+ }
+
+ public ASMifier visitTypeAnnotation(final String method, final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ buf.setLength(0);
+ buf.append("{\n").append("av0 = ").append(name).append(".")
+ .append(method).append("(");
+ buf.append(typeRef);
+ buf.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
+ appendConstant(desc);
+ buf.append(", ").append(visible).append(");\n");
+ text.add(buf.toString());
+ ASMifier a = createASMifier("av", 0);
+ text.add(a.getText());
+ text.add("}\n");
+ return a;
+ }
+
public void visitAttribute(final Attribute attr) {
buf.setLength(0);
buf.append("// ATTRIBUTE ").append(attr.type).append('\n');
@@ -809,7 +935,7 @@ public class ASMifier extends Printer {
// ------------------------------------------------------------------------
protected ASMifier createASMifier(final String name, final int id) {
- return new ASMifier(Opcodes.ASM4, name, id);
+ return new ASMifier(Opcodes.ASM5, name, id);
}
/**
@@ -950,6 +1076,13 @@ public class ASMifier extends Printer {
buf.append("ACC_DEPRECATED");
first = false;
}
+ if ((access & Opcodes.ACC_MANDATED) != 0) {
+ if (!first) {
+ buf.append(" + ");
+ }
+ buf.append("ACC_MANDATED");
+ first = false;
+ }
if (first) {
buf.append('0');
}
diff --git a/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java b/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java
index f00a8f04a2..70441d1df4 100644
--- a/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckAnnotationAdapter.java
@@ -49,7 +49,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor {
}
CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) {
- super(Opcodes.ASM4, av);
+ super(Opcodes.ASM5, av);
this.named = named;
}
@@ -70,7 +70,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor {
}
if (value instanceof Type) {
int sort = ((Type) value).getSort();
- if (sort != Type.OBJECT && sort != Type.ARRAY) {
+ if (sort == Type.METHOD) {
throw new IllegalArgumentException("Invalid annotation value");
}
}
diff --git a/src/asm/scala/tools/asm/util/CheckClassAdapter.java b/src/asm/scala/tools/asm/util/CheckClassAdapter.java
index 0bfa143a95..9909208cc4 100644
--- a/src/asm/scala/tools/asm/util/CheckClassAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckClassAdapter.java
@@ -46,6 +46,8 @@ import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
import scala.tools.asm.tree.ClassNode;
import scala.tools.asm.tree.MethodNode;
import scala.tools.asm.tree.analysis.Analyzer;
@@ -91,9 +93,9 @@ import scala.tools.asm.tree.analysis.SimpleVerifier;
* insnNumber locals : stack):
*
* <pre>
- * scala.tools.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
- * at scala.tools.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
- * at scala.tools.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
+ * org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
+ * at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
+ * at org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
* ...
* remove()V
* 00000 LinkedBlockingQueue$Itr . . . . . . . . :
@@ -106,7 +108,7 @@ import scala.tools.asm.tree.analysis.SimpleVerifier;
* 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . :
* ILOAD 1
* 00072 <b>?</b>
- * INVOKESPECIAL java/lang/Integer.<init> (I)V
+ * INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
* ...
* </pre>
*
@@ -215,7 +217,7 @@ public class CheckClassAdapter extends ClassVisitor {
List<Type> interfaces = new ArrayList<Type>();
for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
- interfaces.add(Type.getObjectType(i.next().toString()));
+ interfaces.add(Type.getObjectType(i.next()));
}
for (int i = 0; i < methods.size(); ++i) {
@@ -328,9 +330,14 @@ public class CheckClassAdapter extends ClassVisitor {
* <tt>false</tt> to not perform any data flow check (see
* {@link CheckMethodAdapter}). This option requires valid
* maxLocals and maxStack values.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
- this(Opcodes.ASM4, cv, checkDataFlow);
+ this(Opcodes.ASM5, cv, checkDataFlow);
+ if (getClass() != CheckClassAdapter.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -338,7 +345,7 @@ public class CheckClassAdapter extends ClassVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param cv
* the class visitor to which this adapter must delegate calls.
* @param checkDataFlow
@@ -440,7 +447,15 @@ public class CheckClassAdapter extends ClassVisitor {
CheckMethodAdapter.checkInternalName(outerName, "outer class name");
}
if (innerName != null) {
- CheckMethodAdapter.checkIdentifier(innerName, "inner class name");
+ int start = 0;
+ while (start < innerName.length()
+ && Character.isDigit(innerName.charAt(start))) {
+ start++;
+ }
+ if (start == 0 || start < innerName.length()) {
+ CheckMethodAdapter.checkIdentifier(innerName, start, -1,
+ "inner class name");
+ }
}
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
@@ -517,6 +532,23 @@ public class CheckClassAdapter extends ClassVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkState();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.CLASS_TYPE_PARAMETER
+ && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
+ && sort != TypeReference.CLASS_EXTENDS) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
checkState();
if (attr == null) {
@@ -661,6 +693,77 @@ public class CheckClassAdapter extends ClassVisitor {
}
/**
+ * Checks the reference to a type in a type annotation.
+ *
+ * @param typeRef
+ * a reference to an annotated type.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ */
+ static void checkTypeRefAndPath(int typeRef, TypePath typePath) {
+ int mask = 0;
+ switch (typeRef >>> 24) {
+ case TypeReference.CLASS_TYPE_PARAMETER:
+ case TypeReference.METHOD_TYPE_PARAMETER:
+ case TypeReference.METHOD_FORMAL_PARAMETER:
+ mask = 0xFFFF0000;
+ break;
+ case TypeReference.FIELD:
+ case TypeReference.METHOD_RETURN:
+ case TypeReference.METHOD_RECEIVER:
+ case TypeReference.LOCAL_VARIABLE:
+ case TypeReference.RESOURCE_VARIABLE:
+ case TypeReference.INSTANCEOF:
+ case TypeReference.NEW:
+ case TypeReference.CONSTRUCTOR_REFERENCE:
+ case TypeReference.METHOD_REFERENCE:
+ mask = 0xFF000000;
+ break;
+ case TypeReference.CLASS_EXTENDS:
+ case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+ case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+ case TypeReference.THROWS:
+ case TypeReference.EXCEPTION_PARAMETER:
+ mask = 0xFFFFFF00;
+ break;
+ case TypeReference.CAST:
+ case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+ case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+ case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+ mask = 0xFF0000FF;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(typeRef >>> 24));
+ }
+ if ((typeRef & ~mask) != 0) {
+ throw new IllegalArgumentException("Invalid type reference 0x"
+ + Integer.toHexString(typeRef));
+ }
+ if (typePath != null) {
+ for (int i = 0; i < typePath.getLength(); ++i) {
+ int step = typePath.getStep(i);
+ if (step != TypePath.ARRAY_ELEMENT
+ && step != TypePath.INNER_TYPE
+ && step != TypePath.TYPE_ARGUMENT
+ && step != TypePath.WILDCARD_BOUND) {
+ throw new IllegalArgumentException(
+ "Invalid type path step " + i + " in " + typePath);
+ }
+ if (step != TypePath.TYPE_ARGUMENT
+ && typePath.getStepArgument(i) != 0) {
+ throw new IllegalArgumentException(
+ "Invalid type path step argument for step " + i
+ + " in " + typePath);
+ }
+ }
+ }
+ }
+
+ /**
* Checks the formal type parameters of a class or method signature.
*
* @param signature
diff --git a/src/asm/scala/tools/asm/util/CheckFieldAdapter.java b/src/asm/scala/tools/asm/util/CheckFieldAdapter.java
index 4657605936..e682df47af 100644
--- a/src/asm/scala/tools/asm/util/CheckFieldAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckFieldAdapter.java
@@ -33,6 +33,8 @@ import scala.tools.asm.AnnotationVisitor;
import scala.tools.asm.Attribute;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
/**
* A {@link FieldVisitor} that checks that its methods are properly used.
@@ -48,9 +50,14 @@ public class CheckFieldAdapter extends FieldVisitor {
*
* @param fv
* the field visitor to which this adapter must delegate calls.
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public CheckFieldAdapter(final FieldVisitor fv) {
- this(Opcodes.ASM4, fv);
+ this(Opcodes.ASM5, fv);
+ if (getClass() != CheckFieldAdapter.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -58,7 +65,7 @@ public class CheckFieldAdapter extends FieldVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param fv
* the field visitor to which this adapter must delegate calls.
*/
@@ -75,6 +82,21 @@ public class CheckFieldAdapter extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkEnd();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.FIELD) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
checkEnd();
if (attr == null) {
diff --git a/src/asm/scala/tools/asm/util/CheckMethodAdapter.java b/src/asm/scala/tools/asm/util/CheckMethodAdapter.java
index 9da01c9d6e..131dfa5e5b 100644
--- a/src/asm/scala/tools/asm/util/CheckMethodAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckMethodAdapter.java
@@ -46,6 +46,8 @@ import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
import scala.tools.asm.tree.MethodNode;
import scala.tools.asm.tree.analysis.Analyzer;
import scala.tools.asm.tree.analysis.BasicValue;
@@ -390,10 +392,15 @@ public class CheckMethodAdapter extends MethodVisitor {
* the method visitor to which this adapter must delegate calls.
* @param labels
* a map of already visited labels (in other methods).
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public CheckMethodAdapter(final MethodVisitor mv,
final Map<Label, Integer> labels) {
- this(Opcodes.ASM4, mv, labels);
+ this(Opcodes.ASM5, mv, labels);
+ if (getClass() != CheckMethodAdapter.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -434,7 +441,7 @@ public class CheckMethodAdapter extends MethodVisitor {
public CheckMethodAdapter(final int access, final String name,
final String desc, final MethodVisitor cmv,
final Map<Label, Integer> labels) {
- this(new MethodNode(access, name, desc, null, null) {
+ this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
@Override
public void visitEnd() {
Analyzer<BasicValue> a = new Analyzer<BasicValue>(
@@ -462,6 +469,16 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public void visitParameter(String name, int access) {
+ if (name != null) {
+ checkUnqualifiedName(version, name, "name");
+ }
+ CheckClassAdapter.checkAccess(access, Opcodes.ACC_FINAL
+ + Opcodes.ACC_MANDATED + Opcodes.ACC_SYNTHETIC);
+ super.visitParameter(name, access);
+ }
+
+ @Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
checkEndMethod();
@@ -470,6 +487,26 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkEndMethod();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.METHOD_TYPE_PARAMETER
+ && sort != TypeReference.METHOD_TYPE_PARAMETER_BOUND
+ && sort != TypeReference.METHOD_RETURN
+ && sort != TypeReference.METHOD_RECEIVER
+ && sort != TypeReference.METHOD_FORMAL_PARAMETER
+ && sort != TypeReference.THROWS) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public AnnotationVisitor visitAnnotationDefault() {
checkEndMethod();
return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false);
@@ -647,9 +684,30 @@ public class CheckMethodAdapter extends MethodVisitor {
++insnCount;
}
+ @Deprecated
@Override
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc,
+ opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ private void doVisitMethodInsn(int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
checkStartCode();
checkEndCode();
checkOpcode(opcode, 5);
@@ -658,7 +716,21 @@ public class CheckMethodAdapter extends MethodVisitor {
}
checkInternalName(owner, "owner");
checkMethodDesc(desc);
- super.visitMethodInsn(opcode, owner, name, desc);
+ if (opcode == Opcodes.INVOKEVIRTUAL && itf) {
+ throw new IllegalArgumentException(
+ "INVOKEVIRTUAL can't be used with interfaces");
+ }
+ if (opcode == Opcodes.INVOKEINTERFACE && !itf) {
+ throw new IllegalArgumentException(
+ "INVOKEINTERFACE can't be used with classes");
+ }
+ // Calling super.visitMethodInsn requires to call the correct version
+ // depending on this.api (otherwise infinite loops can occur). To
+ // simplify and to make it easier to automatically remove the backward
+ // compatibility code, we inline the code of the overridden method here.
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
++insnCount;
}
@@ -797,6 +869,29 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkStartCode();
+ checkEndCode();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.INSTANCEOF && sort != TypeReference.NEW
+ && sort != TypeReference.CONSTRUCTOR_REFERENCE
+ && sort != TypeReference.METHOD_REFERENCE
+ && sort != TypeReference.CAST
+ && sort != TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
+ && sort != TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT
+ && sort != TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
+ && sort != TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitInsnAnnotation(typeRef,
+ typePath, desc, visible));
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
checkStartCode();
@@ -821,6 +916,22 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ checkStartCode();
+ checkEndCode();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.EXCEPTION_PARAMETER) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ CheckMethodAdapter.checkDesc(desc, false);
+ return new CheckAnnotationAdapter(super.visitTryCatchAnnotation(
+ typeRef, typePath, desc, visible));
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -841,6 +952,40 @@ public class CheckMethodAdapter extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ checkStartCode();
+ checkEndCode();
+ int sort = typeRef >>> 24;
+ if (sort != TypeReference.LOCAL_VARIABLE
+ && sort != TypeReference.RESOURCE_VARIABLE) {
+ throw new IllegalArgumentException("Invalid type reference sort 0x"
+ + Integer.toHexString(sort));
+ }
+ CheckClassAdapter.checkTypeRefAndPath(typeRef, typePath);
+ checkDesc(desc, false);
+ if (start == null || end == null || index == null
+ || end.length != start.length || index.length != start.length) {
+ throw new IllegalArgumentException(
+ "Invalid start, end and index arrays (must be non null and of identical length");
+ }
+ for (int i = 0; i < start.length; ++i) {
+ checkLabel(start[i], true, "start label");
+ checkLabel(end[i], true, "end label");
+ checkUnsignedShort(index[i], "Invalid variable index");
+ int s = labels.get(start[i]).intValue();
+ int e = labels.get(end[i]).intValue();
+ if (e < s) {
+ throw new IllegalArgumentException(
+ "Invalid start and end labels (end must be greater than start)");
+ }
+ }
+ return super.visitLocalVariableAnnotation(typeRef, typePath, start,
+ end, index, desc, visible);
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
checkStartCode();
checkEndCode();
@@ -1202,7 +1347,7 @@ public class CheckMethodAdapter extends MethodVisitor {
checkIdentifier(name, begin, slash, null);
begin = slash + 1;
} while (slash != max);
- } catch (IllegalArgumentException _) {
+ } catch (IllegalArgumentException unused) {
throw new IllegalArgumentException(
"Invalid "
+ msg
@@ -1280,7 +1425,7 @@ public class CheckMethodAdapter extends MethodVisitor {
}
try {
checkInternalName(desc, start + 1, index, null);
- } catch (IllegalArgumentException _) {
+ } catch (IllegalArgumentException unused) {
throw new IllegalArgumentException("Invalid descriptor: "
+ desc);
}
diff --git a/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java b/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java
index e69302b8a6..54c9033c90 100644
--- a/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java
+++ b/src/asm/scala/tools/asm/util/CheckSignatureAdapter.java
@@ -113,7 +113,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
* <tt>null</tt>.
*/
public CheckSignatureAdapter(final int type, final SignatureVisitor sv) {
- this(Opcodes.ASM4, type, sv);
+ this(Opcodes.ASM5, type, sv);
}
/**
@@ -121,7 +121,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @param type
* the type of signature to be checked. See
* {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
diff --git a/src/asm/scala/tools/asm/util/Printer.java b/src/asm/scala/tools/asm/util/Printer.java
index 86e0f9e122..4135672c6b 100644
--- a/src/asm/scala/tools/asm/util/Printer.java
+++ b/src/asm/scala/tools/asm/util/Printer.java
@@ -37,6 +37,7 @@ import scala.tools.asm.Attribute;
import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* An abstract converter from visit events to text.
@@ -116,7 +117,7 @@ public abstract class Printer {
/**
* The ASM API version implemented by this class. The value of this field
- * must be one of {@link Opcodes#ASM4}.
+ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected final int api;
@@ -175,6 +176,15 @@ public abstract class Printer {
final boolean visible);
/**
+ * Class type annotation. See
+ * {@link scala.tools.asm.ClassVisitor#visitTypeAnnotation}.
+ */
+ public Printer visitClassTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Class attribute. See
* {@link scala.tools.asm.ClassVisitor#visitAttribute}.
*/
@@ -249,6 +259,15 @@ public abstract class Printer {
final boolean visible);
/**
+ * Field type annotation. See
+ * {@link scala.tools.asm.FieldVisitor#visitTypeAnnotation}.
+ */
+ public Printer visitFieldTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Field attribute. See
* {@link scala.tools.asm.FieldVisitor#visitAttribute}.
*/
@@ -264,6 +283,14 @@ public abstract class Printer {
// ------------------------------------------------------------------------
/**
+ * Method parameter. See
+ * {@link scala.tools.asm.MethodVisitor#visitParameter(String, int)}.
+ */
+ public void visitParameter(String name, int access) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method default annotation. See
* {@link scala.tools.asm.MethodVisitor#visitAnnotationDefault}.
*/
@@ -277,6 +304,15 @@ public abstract class Printer {
final boolean visible);
/**
+ * Method type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitTypeAnnotation}.
+ */
+ public Printer visitMethodTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method parameter annotation. See
* {@link scala.tools.asm.MethodVisitor#visitParameterAnnotation}.
*/
@@ -336,8 +372,33 @@ public abstract class Printer {
* Method instruction. See
* {@link scala.tools.asm.MethodVisitor#visitMethodInsn}.
*/
- public abstract void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc);
+ @Deprecated
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc) {
+ if (api >= Opcodes.ASM5) {
+ boolean itf = opcode == Opcodes.INVOKEINTERFACE;
+ visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
+ * Method instruction. See
+ * {@link scala.tools.asm.MethodVisitor#visitMethodInsn}.
+ */
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
+ if (api < Opcodes.ASM5) {
+ if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
+ throw new IllegalArgumentException(
+ "INVOKESPECIAL/STATIC on interfaces require ASM 5");
+ }
+ visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ throw new RuntimeException("Must be overriden");
+ }
/**
* Method instruction. See
@@ -391,6 +452,15 @@ public abstract class Printer {
final int dims);
/**
+ * Instruction type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitInsnAnnotation}.
+ */
+ public Printer visitInsnAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method exception handler. See
* {@link scala.tools.asm.MethodVisitor#visitTryCatchBlock}.
*/
@@ -398,6 +468,15 @@ public abstract class Printer {
final Label handler, final String type);
/**
+ * Try catch block type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitTryCatchAnnotation}.
+ */
+ public Printer visitTryCatchAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method debug info. See
* {@link scala.tools.asm.MethodVisitor#visitLocalVariable}.
*/
@@ -406,6 +485,16 @@ public abstract class Printer {
final Label end, final int index);
/**
+ * Local variable type annotation. See
+ * {@link scala.tools.asm.MethodVisitor#visitTryCatchAnnotation}.
+ */
+ public Printer visitLocalVariableAnnotation(final int typeRef,
+ final TypePath typePath, final Label[] start, final Label[] end,
+ final int[] index, final String desc, final boolean visible) {
+ throw new RuntimeException("Must be overriden");
+ }
+
+ /**
* Method debug info. See
* {@link scala.tools.asm.MethodVisitor#visitLineNumber}.
*/
diff --git a/src/asm/scala/tools/asm/util/Textifier.java b/src/asm/scala/tools/asm/util/Textifier.java
index a5c4f6779e..373e46f5ed 100644
--- a/src/asm/scala/tools/asm/util/Textifier.java
+++ b/src/asm/scala/tools/asm/util/Textifier.java
@@ -40,6 +40,8 @@ import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.Opcodes;
import scala.tools.asm.Type;
+import scala.tools.asm.TypePath;
+import scala.tools.asm.TypeReference;
import scala.tools.asm.signature.SignatureReader;
/**
@@ -135,15 +137,26 @@ public class Textifier extends Printer {
*/
protected Map<Label, String> labelNames;
+ /**
+ * Class access flags
+ */
+ private int access;
+
private int valueNumber = 0;
/**
* Constructs a new {@link Textifier}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #Textifier(int)}
* version.
+ *
+ * @throws IllegalStateException
+ * If a subclass calls this constructor.
*/
public Textifier() {
- this(Opcodes.ASM4);
+ this(Opcodes.ASM5);
+ if (getClass() != Textifier.class) {
+ throw new IllegalStateException();
+ }
}
/**
@@ -151,7 +164,7 @@ public class Textifier extends Printer {
*
* @param api
* the ASM API version implemented by this visitor. Must be one
- * of {@link Opcodes#ASM4}.
+ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
*/
protected Textifier(final int api) {
super(api);
@@ -208,6 +221,7 @@ public class Textifier extends Printer {
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
+ this.access = access;
int major = version & 0xFFFF;
int minor = version >>> 16;
buf.setLength(0);
@@ -294,6 +308,13 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ text.add("\n");
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitClassAttribute(final Attribute attr) {
text.add("\n");
visitAttribute(attr);
@@ -393,7 +414,7 @@ public class Textifier extends Printer {
}
buf.append(tab);
- appendAccess(access);
+ appendAccess(access & ~Opcodes.ACC_VOLATILE);
if ((access & Opcodes.ACC_NATIVE) != 0) {
buf.append("native ");
}
@@ -403,6 +424,11 @@ public class Textifier extends Printer {
if ((access & Opcodes.ACC_BRIDGE) != 0) {
buf.append("bridge ");
}
+ if ((this.access & Opcodes.ACC_INTERFACE) != 0
+ && (access & Opcodes.ACC_ABSTRACT) == 0
+ && (access & Opcodes.ACC_STATIC) == 0) {
+ buf.append("default ");
+ }
buf.append(name);
appendDescriptor(METHOD_DESCRIPTOR, desc);
@@ -617,6 +643,12 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitFieldAttribute(final Attribute attr) {
visitAttribute(attr);
}
@@ -630,6 +662,16 @@ public class Textifier extends Printer {
// ------------------------------------------------------------------------
@Override
+ public void visitParameter(final String name, final int access) {
+ buf.setLength(0);
+ buf.append(tab2).append("// parameter ");
+ appendAccess(access);
+ buf.append(' ').append((name == null) ? "<no name>" : name)
+ .append('\n');
+ text.add(buf.toString());
+ }
+
+ @Override
public Textifier visitAnnotationDefault() {
text.add(tab2 + "default=");
Textifier t = createTextifier();
@@ -645,6 +687,12 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public Textifier visitParameterAnnotation(final int parameter,
final String desc, final boolean visible) {
buf.setLength(0);
@@ -761,9 +809,30 @@ public class Textifier extends Printer {
text.add(buf.toString());
}
+ @Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc,
+ opcode == Opcodes.INVOKEINTERFACE);
+ }
+
+ @Override
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ doVisitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ private void doVisitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc, final boolean itf) {
buf.setLength(0);
buf.append(tab2).append(OPCODES[opcode]).append(' ');
appendDescriptor(INTERNAL_NAME, owner);
@@ -781,26 +850,35 @@ public class Textifier extends Printer {
buf.append(name);
appendDescriptor(METHOD_DESCRIPTOR, desc);
buf.append(" [");
+ buf.append('\n');
+ buf.append(tab3);
appendHandle(bsm);
+ buf.append('\n');
buf.append(tab3).append("// arguments:");
if (bsmArgs.length == 0) {
buf.append(" none");
} else {
- buf.append('\n').append(tab3);
+ buf.append('\n');
for (int i = 0; i < bsmArgs.length; i++) {
+ buf.append(tab3);
Object cst = bsmArgs[i];
if (cst instanceof String) {
Printer.appendString(buf, (String) cst);
} else if (cst instanceof Type) {
- buf.append(((Type) cst).getDescriptor()).append(".class");
+ Type type = (Type) cst;
+ if(type.getSort() == Type.METHOD){
+ appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
+ } else {
+ buf.append(type.getDescriptor()).append(".class");
+ }
} else if (cst instanceof Handle) {
appendHandle((Handle) cst);
} else {
buf.append(cst);
}
- buf.append(", ");
+ buf.append(", \n");
}
- buf.setLength(buf.length() - 2);
+ buf.setLength(buf.length() - 3);
}
buf.append('\n');
buf.append(tab2).append("]\n");
@@ -890,6 +968,12 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitInsnAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ return visitTypeAnnotation(typeRef, typePath, desc, visible);
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
buf.setLength(0);
@@ -906,6 +990,25 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath,
+ String desc, boolean visible) {
+ buf.setLength(0);
+ buf.append(tab2).append("TRYCATCHBLOCK @");
+ appendDescriptor(FIELD_DESCRIPTOR, desc);
+ buf.append('(');
+ text.add(buf.toString());
+ Textifier t = createTextifier();
+ text.add(t.getText());
+ buf.setLength(0);
+ buf.append(") : ");
+ appendTypeReference(typeRef);
+ buf.append(", ").append(typePath);
+ buf.append(visible ? "\n" : " // invisible\n");
+ text.add(buf.toString());
+ return t;
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -932,6 +1035,33 @@ public class Textifier extends Printer {
}
@Override
+ public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath,
+ Label[] start, Label[] end, int[] index, String desc,
+ boolean visible) {
+ buf.setLength(0);
+ buf.append(tab2).append("LOCALVARIABLE @");
+ appendDescriptor(FIELD_DESCRIPTOR, desc);
+ buf.append('(');
+ text.add(buf.toString());
+ Textifier t = createTextifier();
+ text.add(t.getText());
+ buf.setLength(0);
+ buf.append(") : ");
+ appendTypeReference(typeRef);
+ buf.append(", ").append(typePath);
+ for (int i = 0; i < start.length; ++i) {
+ buf.append(" [ ");
+ appendLabel(start[i]);
+ buf.append(" - ");
+ appendLabel(end[i]);
+ buf.append(" - ").append(index[i]).append(" ]");
+ }
+ buf.append(visible ? "\n" : " // invisible\n");
+ text.add(buf.toString());
+ return t;
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
buf.setLength(0);
buf.append(tab2).append("LINENUMBER ").append(line).append(' ');
@@ -981,6 +1111,39 @@ public class Textifier extends Printer {
}
/**
+ * Prints a disassembled view of the given type annotation.
+ *
+ * @param typeRef
+ * a reference to the annotated type. See {@link TypeReference}.
+ * @param typePath
+ * the path to the annotated type argument, wildcard bound, array
+ * element type, or static inner type within 'typeRef'. May be
+ * <tt>null</tt> if the annotation targets 'typeRef' as a whole.
+ * @param desc
+ * the class descriptor of the annotation class.
+ * @param visible
+ * <tt>true</tt> if the annotation is visible at runtime.
+ * @return a visitor to visit the annotation values.
+ */
+ public Textifier visitTypeAnnotation(final int typeRef,
+ final TypePath typePath, final String desc, final boolean visible) {
+ buf.setLength(0);
+ buf.append(tab).append('@');
+ appendDescriptor(FIELD_DESCRIPTOR, desc);
+ buf.append('(');
+ text.add(buf.toString());
+ Textifier t = createTextifier();
+ text.add(t.getText());
+ buf.setLength(0);
+ buf.append(") : ");
+ appendTypeReference(typeRef);
+ buf.append(", ").append(typePath);
+ buf.append(visible ? "\n" : " // invisible\n");
+ text.add(buf.toString());
+ return t;
+ }
+
+ /**
* Prints a disassembled view of the given attribute.
*
* @param attr
@@ -1061,10 +1224,10 @@ public class Textifier extends Printer {
* a handle, non null.
*/
protected void appendHandle(final Handle h) {
- buf.append('\n').append(tab3);
int tag = h.getTag();
buf.append("// handle kind 0x").append(Integer.toHexString(tag))
.append(" : ");
+ boolean isMethodHandle = false;
switch (tag) {
case Opcodes.H_GETFIELD:
buf.append("GETFIELD");
@@ -1080,18 +1243,23 @@ public class Textifier extends Printer {
break;
case Opcodes.H_INVOKEINTERFACE:
buf.append("INVOKEINTERFACE");
+ isMethodHandle = true;
break;
case Opcodes.H_INVOKESPECIAL:
buf.append("INVOKESPECIAL");
+ isMethodHandle = true;
break;
case Opcodes.H_INVOKESTATIC:
buf.append("INVOKESTATIC");
+ isMethodHandle = true;
break;
case Opcodes.H_INVOKEVIRTUAL:
buf.append("INVOKEVIRTUAL");
+ isMethodHandle = true;
break;
case Opcodes.H_NEWINVOKESPECIAL:
buf.append("NEWINVOKESPECIAL");
+ isMethodHandle = true;
break;
}
buf.append('\n');
@@ -1099,9 +1267,13 @@ public class Textifier extends Printer {
appendDescriptor(INTERNAL_NAME, h.getOwner());
buf.append('.');
buf.append(h.getName());
- buf.append('(');
+ if(!isMethodHandle){
+ buf.append('(');
+ }
appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
- buf.append(')').append('\n');
+ if(!isMethodHandle){
+ buf.append(')');
+ }
}
/**
@@ -1145,6 +1317,9 @@ public class Textifier extends Printer {
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
buf.append("synthetic ");
}
+ if ((access & Opcodes.ACC_MANDATED) != 0) {
+ buf.append("mandated ");
+ }
if ((access & Opcodes.ACC_ENUM) != 0) {
buf.append("enum ");
}
@@ -1156,6 +1331,90 @@ public class Textifier extends Printer {
}
}
+ private void appendTypeReference(final int typeRef) {
+ TypeReference ref = new TypeReference(typeRef);
+ switch (ref.getSort()) {
+ case TypeReference.CLASS_TYPE_PARAMETER:
+ buf.append("CLASS_TYPE_PARAMETER ").append(
+ ref.getTypeParameterIndex());
+ break;
+ case TypeReference.METHOD_TYPE_PARAMETER:
+ buf.append("METHOD_TYPE_PARAMETER ").append(
+ ref.getTypeParameterIndex());
+ break;
+ case TypeReference.CLASS_EXTENDS:
+ buf.append("CLASS_EXTENDS ").append(ref.getSuperTypeIndex());
+ break;
+ case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
+ buf.append("CLASS_TYPE_PARAMETER_BOUND ")
+ .append(ref.getTypeParameterIndex()).append(", ")
+ .append(ref.getTypeParameterBoundIndex());
+ break;
+ case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
+ buf.append("METHOD_TYPE_PARAMETER_BOUND ")
+ .append(ref.getTypeParameterIndex()).append(", ")
+ .append(ref.getTypeParameterBoundIndex());
+ break;
+ case TypeReference.FIELD:
+ buf.append("FIELD");
+ break;
+ case TypeReference.METHOD_RETURN:
+ buf.append("METHOD_RETURN");
+ break;
+ case TypeReference.METHOD_RECEIVER:
+ buf.append("METHOD_RECEIVER");
+ break;
+ case TypeReference.METHOD_FORMAL_PARAMETER:
+ buf.append("METHOD_FORMAL_PARAMETER ").append(
+ ref.getFormalParameterIndex());
+ break;
+ case TypeReference.THROWS:
+ buf.append("THROWS ").append(ref.getExceptionIndex());
+ break;
+ case TypeReference.LOCAL_VARIABLE:
+ buf.append("LOCAL_VARIABLE");
+ break;
+ case TypeReference.RESOURCE_VARIABLE:
+ buf.append("RESOURCE_VARIABLE");
+ break;
+ case TypeReference.EXCEPTION_PARAMETER:
+ buf.append("EXCEPTION_PARAMETER ").append(
+ ref.getTryCatchBlockIndex());
+ break;
+ case TypeReference.INSTANCEOF:
+ buf.append("INSTANCEOF");
+ break;
+ case TypeReference.NEW:
+ buf.append("NEW");
+ break;
+ case TypeReference.CONSTRUCTOR_REFERENCE:
+ buf.append("CONSTRUCTOR_REFERENCE");
+ break;
+ case TypeReference.METHOD_REFERENCE:
+ buf.append("METHOD_REFERENCE");
+ break;
+ case TypeReference.CAST:
+ buf.append("CAST ").append(ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ buf.append("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
+ buf.append("METHOD_INVOCATION_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
+ buf.append("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
+ buf.append("METHOD_REFERENCE_TYPE_ARGUMENT ").append(
+ ref.getTypeArgumentIndex());
+ break;
+ }
+ }
+
private void appendFrameTypes(final int n, final Object[] o) {
for (int i = 0; i < n; ++i) {
if (i > 0) {
diff --git a/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java b/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java
index 33e7cf0b26..7a9dbfef06 100644
--- a/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceAnnotationVisitor.java
@@ -47,7 +47,7 @@ public final class TraceAnnotationVisitor extends AnnotationVisitor {
}
public TraceAnnotationVisitor(final AnnotationVisitor av, final Printer p) {
- super(Opcodes.ASM4, av);
+ super(Opcodes.ASM5, av);
this.p = p;
}
diff --git a/src/asm/scala/tools/asm/util/TraceClassVisitor.java b/src/asm/scala/tools/asm/util/TraceClassVisitor.java
index ff7a017482..842d286672 100644
--- a/src/asm/scala/tools/asm/util/TraceClassVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceClassVisitor.java
@@ -37,6 +37,7 @@ import scala.tools.asm.ClassVisitor;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A {@link ClassVisitor} that prints the classes it visits with a
@@ -130,7 +131,7 @@ public final class TraceClassVisitor extends ClassVisitor {
*/
public TraceClassVisitor(final ClassVisitor cv, final Printer p,
final PrintWriter pw) {
- super(Opcodes.ASM4, cv);
+ super(Opcodes.ASM5, cv);
this.pw = pw;
this.p = p;
}
@@ -166,6 +167,16 @@ public final class TraceClassVisitor extends ClassVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitClassTypeAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = cv == null ? null : cv.visitTypeAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
p.visitClassAttribute(attr);
super.visitAttribute(attr);
diff --git a/src/asm/scala/tools/asm/util/TraceFieldVisitor.java b/src/asm/scala/tools/asm/util/TraceFieldVisitor.java
index 9547a70008..1d0743a424 100644
--- a/src/asm/scala/tools/asm/util/TraceFieldVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceFieldVisitor.java
@@ -33,6 +33,7 @@ import scala.tools.asm.AnnotationVisitor;
import scala.tools.asm.Attribute;
import scala.tools.asm.FieldVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A {@link FieldVisitor} that prints the fields it visits with a
@@ -49,7 +50,7 @@ public final class TraceFieldVisitor extends FieldVisitor {
}
public TraceFieldVisitor(final FieldVisitor fv, final Printer p) {
- super(Opcodes.ASM4, fv);
+ super(Opcodes.ASM5, fv);
this.p = p;
}
@@ -63,6 +64,16 @@ public final class TraceFieldVisitor extends FieldVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitFieldTypeAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = fv == null ? null : fv.visitTypeAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
p.visitFieldAttribute(attr);
super.visitAttribute(attr);
diff --git a/src/asm/scala/tools/asm/util/TraceMethodVisitor.java b/src/asm/scala/tools/asm/util/TraceMethodVisitor.java
index 9034567c8f..db5f051003 100644
--- a/src/asm/scala/tools/asm/util/TraceMethodVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceMethodVisitor.java
@@ -35,6 +35,7 @@ import scala.tools.asm.Handle;
import scala.tools.asm.Label;
import scala.tools.asm.MethodVisitor;
import scala.tools.asm.Opcodes;
+import scala.tools.asm.TypePath;
/**
* A {@link MethodVisitor} that prints the methods it visits with a
@@ -51,11 +52,17 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
public TraceMethodVisitor(final MethodVisitor mv, final Printer p) {
- super(Opcodes.ASM4, mv);
+ super(Opcodes.ASM5, mv);
this.p = p;
}
@Override
+ public void visitParameter(String name, int access) {
+ p.visitParameter(name, access);
+ super.visitParameter(name, access);
+ }
+
+ @Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
Printer p = this.p.visitMethodAnnotation(desc, visible);
@@ -65,6 +72,16 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTypeAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitMethodTypeAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = mv == null ? null : mv.visitTypeAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitAttribute(final Attribute attr) {
p.visitMethodAttribute(attr);
super.visitAttribute(attr);
@@ -130,11 +147,31 @@ public final class TraceMethodVisitor extends MethodVisitor {
super.visitFieldInsn(opcode, owner, name, desc);
}
+ @Deprecated
@Override
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ if (api >= Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ return;
+ }
p.visitMethodInsn(opcode, owner, name, desc);
- super.visitMethodInsn(opcode, owner, name, desc);
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc);
+ }
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc, boolean itf) {
+ if (api < Opcodes.ASM5) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ return;
+ }
+ p.visitMethodInsn(opcode, owner, name, desc, itf);
+ if (mv != null) {
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
}
@Override
@@ -189,6 +226,16 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitInsnAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p
+ .visitInsnAnnotation(typeRef, typePath, desc, visible);
+ AnnotationVisitor av = mv == null ? null : mv.visitInsnAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitTryCatchBlock(final Label start, final Label end,
final Label handler, final String type) {
p.visitTryCatchBlock(start, end, handler, type);
@@ -196,6 +243,16 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
+ TypePath typePath, String desc, boolean visible) {
+ Printer p = this.p.visitTryCatchAnnotation(typeRef, typePath, desc,
+ visible);
+ AnnotationVisitor av = mv == null ? null : mv.visitTryCatchAnnotation(
+ typeRef, typePath, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
@@ -204,6 +261,18 @@ public final class TraceMethodVisitor extends MethodVisitor {
}
@Override
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
+ TypePath typePath, Label[] start, Label[] end, int[] index,
+ String desc, boolean visible) {
+ Printer p = this.p.visitLocalVariableAnnotation(typeRef, typePath,
+ start, end, index, desc, visible);
+ AnnotationVisitor av = mv == null ? null : mv
+ .visitLocalVariableAnnotation(typeRef, typePath, start, end,
+ index, desc, visible);
+ return new TraceAnnotationVisitor(av, p);
+ }
+
+ @Override
public void visitLineNumber(final int line, final Label start) {
p.visitLineNumber(line, start);
super.visitLineNumber(line, start);
diff --git a/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java b/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java
index 1e23c7ef1a..f99ec2b0c2 100644
--- a/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java
+++ b/src/asm/scala/tools/asm/util/TraceSignatureVisitor.java
@@ -75,13 +75,13 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
private String separator = "";
public TraceSignatureVisitor(final int access) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
this.declaration = new StringBuffer();
}
private TraceSignatureVisitor(final StringBuffer buf) {
- super(Opcodes.ASM4);
+ super(Opcodes.ASM5);
this.declaration = buf;
}
diff --git a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala
index 1413065a27..a13a778b2f 100644
--- a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala
+++ b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala
@@ -53,7 +53,7 @@ abstract class DefaultMacroCompiler extends Resolvers
(EmptyTree, TermName(""), Nil)
}
val bundleImplRef = MacroImplRefCompiler(
- atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(maybeBundleRef, List(List(Ident(Predef_???)))), methName), targs)),
+ atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(maybeBundleRef, List(List(Literal(Constant(null))))), methName), targs)),
isImplBundle = true
)
val vanillaResult = tryCompile(vanillaImplRef)
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index 0731d78a9b..689e6405d0 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -74,6 +74,11 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo {
}
}
+ // TODO these overrides, and the slow trickle of bugs that they solve (e.g. SI-8479),
+ // suggest that we should pursue an alternative design in which the DocDef nodes
+ // are eliminated from the tree before typer, and instead are modelled as tree
+ // attachments.
+
/** Is tree legal as a member definition of an interface?
*/
override def isInterfaceMember(tree: Tree): Boolean = tree match {
@@ -81,6 +86,11 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo {
case _ => super.isInterfaceMember(tree)
}
+ override def isConstructorWithDefault(t: Tree) = t match {
+ case DocDef(_, definition) => isConstructorWithDefault(definition)
+ case _ => super.isConstructorWithDefault(t)
+ }
+
/** Is tree a pure (i.e. non-side-effecting) definition?
*/
override def isPureDef(tree: Tree): Boolean = tree match {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 9e631febee..ffc45b21ea 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -654,9 +654,10 @@ self =>
def isIdentExcept(except: Name) = isIdent && in.name != except
def isIdentOf(name: Name) = isIdent && in.name == name
- def isUnaryOp = isIdent && raw.isUnary(in.name)
- def isRawStar = isIdent && in.name == raw.STAR
- def isRawBar = isIdent && in.name == raw.BAR
+ def isUnaryOp = isIdent && raw.isUnary(in.name)
+ def isRawStar = isRawIdent && in.name == raw.STAR
+ def isRawBar = isRawIdent && in.name == raw.BAR
+ def isRawIdent = in.token == IDENTIFIER
def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT
def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw
@@ -1001,19 +1002,30 @@ self =>
}
def infixTypeRest(t: Tree, mode: InfixMode.Value): Tree = {
- if (isIdent && in.name != nme.STAR) {
- val opOffset = in.offset
+ // Detect postfix star for repeated args.
+ // Only RPAREN can follow, but accept COMMA and EQUALS for error's sake.
+ // Take RBRACE as a paren typo.
+ def checkRepeatedParam = if (isRawStar) {
+ lookingAhead (in.token match {
+ case RPAREN | COMMA | EQUALS | RBRACE => t
+ case _ => EmptyTree
+ })
+ } else EmptyTree
+ def asInfix = {
+ val opOffset = in.offset
val leftAssoc = treeInfo.isLeftAssoc(in.name)
- if (mode != InfixMode.FirstOp) checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp)
- val op = identForType()
- val tycon = atPos(opOffset) { Ident(op) }
+ if (mode != InfixMode.FirstOp)
+ checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp)
+ val tycon = atPos(opOffset) { Ident(identForType()) }
newLineOptWhenFollowing(isTypeIntroToken)
def mkOp(t1: Tree) = atPos(t.pos.start, opOffset) { AppliedTypeTree(tycon, List(t, t1)) }
if (leftAssoc)
infixTypeRest(mkOp(compoundType()), InfixMode.LeftOp)
else
mkOp(infixType(InfixMode.RightOp))
- } else t
+ }
+ if (isIdent) checkRepeatedParam orElse asInfix
+ else t
}
/** {{{
diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index 32b5a98b98..7236bf70d5 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -55,8 +55,6 @@ trait JavaPlatform extends Platform {
(sym isNonBottomSubClass BoxedBooleanClass)
}
- def doLoad(cls: ClassPath[AbstractFile]#ClassRep): Boolean = true
-
def needCompile(bin: AbstractFile, src: AbstractFile) =
src.lastModified >= bin.lastModified
}
diff --git a/src/compiler/scala/tools/nsc/backend/Platform.scala b/src/compiler/scala/tools/nsc/backend/Platform.scala
index 499f8a9290..439cc1efb8 100644
--- a/src/compiler/scala/tools/nsc/backend/Platform.scala
+++ b/src/compiler/scala/tools/nsc/backend/Platform.scala
@@ -31,14 +31,6 @@ trait Platform {
def isMaybeBoxed(sym: Symbol): Boolean
/**
- * Tells whether a class should be loaded and entered into the package
- * scope. On .NET, this method returns `false` for all synthetic classes
- * (anonymous classes, implementation classes, module classes), their
- * symtab is encoded in the pickle of another class.
- */
- def doLoad(cls: ClassPath[AbstractFile]#ClassRep): Boolean
-
- /**
* Tells whether a class with both a binary and a source representation
* (found in classpath and in sourcepath) should be re-compiled. Behaves
* on the JVM similar to javac, i.e. if the source file is newer than the classfile,
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 1cea4bedda..0ad3c2c76b 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -13,13 +13,12 @@ import scala.collection.{ mutable, immutable }
import scala.collection.mutable.{ ListBuffer, Buffer }
import scala.tools.nsc.symtab._
import scala.annotation.switch
-import PartialFunction._
/**
* @author Iulian Dragos
* @version 1.0
*/
-abstract class GenICode extends SubComponent {
+abstract class GenICode extends SubComponent {
import global._
import icodes._
import icodes.opcodes._
@@ -30,6 +29,9 @@ abstract class GenICode extends SubComponent {
}
import platform.isMaybeBoxed
+ private val bCodeICodeCommon: jvm.BCodeICodeCommon[global.type] = new jvm.BCodeICodeCommon(global)
+ import bCodeICodeCommon._
+
val phaseName = "icode"
override def newPhase(prev: Phase) = new ICodePhase(prev)
@@ -1326,15 +1328,6 @@ abstract class GenICode extends SubComponent {
List(tree)
}
- /** Some useful equality helpers.
- */
- def isNull(t: Tree) = cond(t) { case Literal(Constant(null)) => true }
- def isLiteral(t: Tree) = cond(t) { case Literal(_) => true }
- def isNonNullExpr(t: Tree) = isLiteral(t) || ((t.symbol ne null) && t.symbol.isModule)
-
- /* If l or r is constant null, returns the other ; otherwise null */
- def ifOneIsNull(l: Tree, r: Tree) = if (isNull(l)) r else if (isNull(r)) l else null
-
/**
* Find the label denoted by `lsym` and enter it in context `ctx`.
*
@@ -1431,11 +1424,18 @@ abstract class GenICode extends SubComponent {
def genZandOrZor(and: Boolean): Boolean = {
val ctxInterm = ctx.newBlock()
- val branchesReachable = if (and) genCond(lhs, ctx, ctxInterm, elseCtx)
+ val lhsBranchesReachable = if (and) genCond(lhs, ctx, ctxInterm, elseCtx)
else genCond(lhs, ctx, thenCtx, ctxInterm)
- ctxInterm.bb killUnless branchesReachable
+ // If lhs is known to throw, we can kill the just created ctxInterm.
+ ctxInterm.bb killUnless lhsBranchesReachable
+
+ val rhsBranchesReachable = genCond(rhs, ctxInterm, thenCtx, elseCtx)
- genCond(rhs, ctxInterm, thenCtx, elseCtx)
+ // Reachable means "it does not always throw", i.e. "it might not throw".
+ // In an expression (a && b) or (a || b), the b branch might not be evaluated.
+ // Such an expression is therefore known to throw only if both expressions throw. Or,
+ // successors are reachable if either of the two is reachable (SI-8625).
+ lhsBranchesReachable || rhsBranchesReachable
}
def genRefEq(isEq: Boolean) = {
val f = genEqEqPrimitive(lhs, rhs, ctx) _
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
new file mode 100644
index 0000000000..856f85d9e3
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
@@ -0,0 +1,53 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.tools.nsc.backend.jvm
+
+import scala.tools.asm.tree.{ClassNode, MethodNode}
+import java.io.PrintWriter
+import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier}
+
+object AsmUtils {
+
+ /**
+ * Print the bytecode of methods generated by GenBCode to the standard output. Only methods
+ * whose name contains `traceMethodPattern` are traced.
+ */
+ final val traceMethodEnabled = false
+ final val traceMethodPattern = ""
+
+ /**
+ * Print the bytecode of classes generated by GenBCode to the standard output.
+ */
+ final val traceClassEnabled = false
+ final val traceClassPattern = ""
+
+ /**
+ * Print the bytedcode of classes as they are serialized by the ASM library. The serialization
+ * performed by `asm.ClassWriter` can change the code generated by GenBCode. For example, it
+ * introduces stack map frames, it computes the maximal stack sizes, and it replaces dead
+ * code by NOPs (see also https://github.com/scala/scala/pull/3726#issuecomment-42861780).
+ */
+ final val traceSerializedClassEnabled = false
+ final val traceSerializedClassPattern = ""
+
+ def traceMethod(mnode: MethodNode): Unit = {
+ println(s"Bytecode for method ${mnode.name}")
+ val p = new Textifier
+ val tracer = new TraceMethodVisitor(p)
+ mnode.accept(tracer)
+ val w = new PrintWriter(System.out)
+ p.print(w)
+ w.flush()
+ }
+
+ def traceClass(cnode: ClassNode): Unit = {
+ println(s"Bytecode for class ${cnode.name}")
+ val w = new PrintWriter(System.out)
+ cnode.accept(new TraceClassVisitor(w))
+ w.flush()
+ }
+
+}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 53142fbd87..3d1b646069 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -23,6 +23,7 @@ import scala.tools.asm
abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
import global._
import definitions._
+ import bCodeICodeCommon._
/*
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
@@ -807,7 +808,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
emit(asm.Opcodes.ATHROW) // ICode enters here into enterIgnoreMode, we'll rely instead on DCE at ClassNode level.
} else if (from.isNullType) {
bc drop from
- mnode.visitInsn(asm.Opcodes.ACONST_NULL)
+ emit(asm.Opcodes.ACONST_NULL)
}
else (from, to) match {
case (BYTE, LONG) | (SHORT, LONG) | (CHAR, LONG) | (INT, LONG) => bc.emitT2T(INT, LONG)
@@ -1020,17 +1021,6 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
tree :: Nil
}
- /* Some useful equality helpers. */
- def isNull(t: Tree) = {
- t match {
- case Literal(Constant(null)) => true
- case _ => false
- }
- }
-
- /* If l or r is constant null, returns the other ; otherwise null */
- def ifOneIsNull(l: Tree, r: Tree) = if (isNull(l)) r else if (isNull(r)) l else null
-
/* Emit code to compare the two top-most stack values using the 'op' operator. */
private def genCJUMP(success: asm.Label, failure: asm.Label, op: TestOp, tk: BType) {
if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
@@ -1200,6 +1190,12 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
// expr == null -> expr eq null
genLoad(l, ObjectReference)
genCZJUMP(success, failure, icodes.EQ, ObjectReference)
+ } else if (isNonNullExpr(l)) {
+ // SI-7852 Avoid null check if L is statically non-null.
+ genLoad(l, ObjectReference)
+ genLoad(r, ObjectReference)
+ genCallMethod(Object_equals, icodes.opcodes.Dynamic)
+ genCZJUMP(success, failure, icodes.NE, BOOL)
} else {
// l == r -> if (l eq null) r eq null else l.equals(r)
val eqEqTempLocal = locals.makeLocal(AnyRefReference, nme.EQEQ_LOCAL_VAR.toString)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala
index cc3265c5f9..aa7e73a36b 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala
@@ -22,6 +22,8 @@ abstract class BCodeGlue extends SubComponent {
import global._
+ protected val bCodeICodeCommon: BCodeICodeCommon[global.type] = new BCodeICodeCommon(global)
+
object BType {
import global.chrs
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 359e5d6c29..3fdb38ce0e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -239,6 +239,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
}
/*
+ * must-single-thread
+ */
+ def serialVUID(csym: Symbol): Option[Long] = csym getAnnotation definitions.SerialVersionUIDAttr collect {
+ case AnnotationInfo(_, _, (_, LiteralAnnotArg(const)) :: Nil) => const.longValue
+ }
+
+ /*
* Populates the InnerClasses JVM attribute with `refedInnerClasses`.
* In addition to inner classes mentioned somewhere in `jclass` (where `jclass` is a class file being emitted)
* `refedInnerClasses` should contain those inner classes defined as direct member classes of `jclass`
@@ -817,7 +824,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
index += jparamType.getSize
}
- mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, asmMethodType(m).getDescriptor)
+ mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, asmMethodType(m).getDescriptor, false)
mirrorMethod.visitInsn(jReturnType.getOpcode(asm.Opcodes.IRETURN))
mirrorMethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -881,13 +888,6 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
val MIN_SWITCH_DENSITY = 0.7
/*
- * must-single-thread
- */
- def serialVUID(csym: Symbol): Option[Long] = csym getAnnotation definitions.SerialVersionUIDAttr collect {
- case AnnotationInfo(_, Literal(const) :: _, _) => const.longValue
- }
-
- /*
* Add public static final field serialVersionUID with value `id`
*
* can-multi-thread
@@ -1108,7 +1108,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
constructor.visitVarInsn(asm.Opcodes.ALOAD, 0)
// push the class
- constructor.visitLdcInsn(exemplar(cls).c)
+ constructor.visitLdcInsn(exemplar(cls).c.toASMType)
// push the string array of field information
constructor.visitLdcInsn(new java.lang.Integer(fieldList.length))
@@ -1122,7 +1122,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
// invoke the superclass constructor, which will do the
// necessary java reflection and create Method objects.
- constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor)
+ constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor, false)
constructor.visitInsn(asm.Opcodes.RETURN)
constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -1187,7 +1187,8 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
asm.Opcodes.INVOKEVIRTUAL,
moduleName,
"CREATOR",
- bt.getDescriptor
+ bt.getDescriptor,
+ false
)
// PUTSTATIC `thisName`.CREATOR;
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeICodeCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeICodeCommon.scala
new file mode 100644
index 0000000000..50d20921d5
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeICodeCommon.scala
@@ -0,0 +1,25 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.tools.nsc.backend.jvm
+
+import scala.tools.nsc.Global
+import PartialFunction._
+
+/**
+ * This trait contains code shared between GenBCode and GenICode that depends on types defined in
+ * the compiler cake (Global).
+ */
+final class BCodeICodeCommon[G <: Global](val global: G) {
+ import global._
+
+ /** Some useful equality helpers. */
+ def isNull(t: Tree) = cond(t) { case Literal(Constant(null)) => true }
+ def isLiteral(t: Tree) = cond(t) { case Literal(_) => true }
+ def isNonNullExpr(t: Tree) = isLiteral(t) || ((t.symbol ne null) && t.symbol.isModule)
+
+ /** If l or r is constant null, returns the other ; otherwise null */
+ def ifOneIsNull(l: Tree, r: Tree) = if (isNull(l)) r else if (isNull(r)) l else null
+}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
index c3492b79a9..f9f6e7c3ff 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
@@ -409,19 +409,19 @@ abstract class BCodeIdiomatic extends BCodeGlue {
// can-multi-thread
final def invokespecial(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false)
}
// can-multi-thread
final def invokestatic(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false)
}
// can-multi-thread
final def invokeinterface(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true)
}
// can-multi-thread
final def invokevirtual(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false)
}
// can-multi-thread
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index 360ce58ecc..a76fa4d7ba 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -14,6 +14,8 @@ import scala.tools.nsc.symtab._
import scala.annotation.switch
import scala.tools.asm
+import scala.tools.asm.util.{TraceMethodVisitor, ASMifier}
+import java.io.PrintWriter
/*
*
@@ -114,9 +116,13 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
addClassFields()
innerClassBufferASM ++= trackMemberClasses(claszSymbol, Nil)
-
gen(cd.impl)
+ addInnerClassesASM(cnode, innerClassBufferASM.toList)
+
+ if (AsmUtils.traceClassEnabled && cnode.name.contains(AsmUtils.traceClassPattern))
+ AsmUtils.traceClass(cnode)
+ cnode.innerClasses
assert(cd.symbol == claszSymbol, "Someone messed up BCodePhase.claszSymbol during genPlainClass().")
} // end of method genPlainClass()
@@ -228,7 +234,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
if (isCZStaticModule) {
clinit.visitTypeInsn(asm.Opcodes.NEW, thisName)
clinit.visitMethodInsn(asm.Opcodes.INVOKESPECIAL,
- thisName, INSTANCE_CONSTRUCTOR_NAME, "()V")
+ thisName, INSTANCE_CONSTRUCTOR_NAME, "()V", false)
}
if (isCZParcelable) { legacyAddCreatorCode(clinit, cnode, thisName) }
clinit.visitInsn(asm.Opcodes.RETURN)
@@ -639,6 +645,10 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
// Note we don't invoke visitMax, thus there are no FrameNode among mnode.instructions.
// The only non-instruction nodes to be found are LabelNode and LineNumberNode.
}
+
+ if (AsmUtils.traceMethodEnabled && mnode.name.contains(AsmUtils.traceMethodPattern))
+ AsmUtils.traceMethod(mnode)
+
mnode = null
} // end of method genDefDef()
@@ -676,7 +686,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val jname = callee.javaSimpleName.toString
val jowner = internalName(callee.owner)
val jtype = asmMethodType(callee).getDescriptor
- insnModB = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESPECIAL, jowner, jname, jtype)
+ insnModB = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESPECIAL, jowner, jname, jtype, false)
}
var insnParcA: asm.tree.AbstractInsnNode = null
@@ -697,7 +707,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val jowner = internalName(callee.owner)
val jname = callee.javaSimpleName.toString
val jtype = asmMethodType(callee).getDescriptor
- insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype)
+ insnParcA = new asm.tree.MethodInsnNode(asm.Opcodes.INVOKESTATIC, jowner, jname, jtype, false)
// PUTSTATIC `thisName`.CREATOR;
insnParcB = new asm.tree.FieldInsnNode(asm.Opcodes.PUTSTATIC, thisName, "CREATOR", andrFieldDescr)
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
index 8e6c09213f..1d29fdee10 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
@@ -1,6 +1,6 @@
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
- * @author Paul Phillips
+ * @author Martin Odersky
*/
package scala.tools.nsc
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index a389816caf..13a5c6413d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -975,7 +975,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
index += jparamType.getSize()
}
- mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, javaType(m).getDescriptor)
+ mirrorMethod.visitMethodInsn(asm.Opcodes.INVOKEVIRTUAL, moduleName, mirrorMethodName, javaType(m).getDescriptor, false)
mirrorMethod.visitInsn(jReturnType.getOpcode(asm.Opcodes.IRETURN))
mirrorMethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
@@ -1061,7 +1061,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
asm.Opcodes.INVOKEVIRTUAL,
moduleName,
androidFieldName.toString,
- asm.Type.getMethodDescriptor(creatorType, Array.empty[asm.Type]: _*)
+ asm.Type.getMethodDescriptor(creatorType, Array.empty[asm.Type]: _*),
+ false
)
// PUTSTATIC `thisName`.CREATOR;
@@ -1142,9 +1143,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
def isParcelableClass = isAndroidParcelableClass(clasz.symbol)
- def serialVUID: Option[Long] = clasz.symbol getAnnotation SerialVersionUIDAttr collect {
- case AnnotationInfo(_, Literal(const) :: _, _) => const.longValue
- }
+ def serialVUID: Option[Long] = genBCode.serialVUID(clasz.symbol)
private def getSuperInterfaces(c: IClass): Array[String] = {
@@ -1523,7 +1522,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
if (isStaticModule(clasz.symbol)) {
clinit.visitTypeInsn(asm.Opcodes.NEW, thisName)
clinit.visitMethodInsn(asm.Opcodes.INVOKESPECIAL,
- thisName, INSTANCE_CONSTRUCTOR_NAME, mdesc_arglessvoid)
+ thisName, INSTANCE_CONSTRUCTOR_NAME, mdesc_arglessvoid, false)
}
if (isParcelableClass) { legacyAddCreatorCode(clinit) }
@@ -1667,16 +1666,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
def rem(tk: TypeKind) { emitPrimitive(remOpcodes, tk) }
def invokespecial(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false)
}
def invokestatic(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false)
}
def invokeinterface(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true)
}
def invokevirtual(owner: String, name: String, desc: String) {
- jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc)
+ jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false)
}
def goTo(label: asm.Label) { jmethod.visitJumpInsn(Opcodes.GOTO, label) }
@@ -2926,7 +2925,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// invoke the superclass constructor, which will do the
// necessary java reflection and create Method objects.
- constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor)
+ constructor.visitMethodInsn(asm.Opcodes.INVOKESPECIAL, "scala/beans/ScalaBeanInfo", INSTANCE_CONSTRUCTOR_NAME, conJType.getDescriptor, false)
constructor.visitInsn(asm.Opcodes.RETURN)
constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index 193100474c..61cf76f524 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -243,6 +243,17 @@ abstract class GenBCode extends BCodeSyncAndTry {
val plainC = SubItem3(plain.name, getByteArray(plain))
val beanC = if (bean == null) null else SubItem3(bean.name, getByteArray(bean))
+ if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) {
+ def readClass(bytes: Array[Byte]): asm.tree.ClassNode = {
+ val node = new asm.tree.ClassNode()
+ new asm.ClassReader(bytes).accept(node, 0)
+ node
+ }
+ if (mirrorC != null) AsmUtils.traceClass(readClass(mirrorC.jclassBytes))
+ AsmUtils.traceClass(readClass(plainC.jclassBytes))
+ if (beanC != null) AsmUtils.traceClass(readClass(beanC.jclassBytes))
+ }
+
q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder)
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index c49f23852f..a866173a88 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -56,11 +56,8 @@ abstract class ClosureElimination extends SubComponent {
case (BOX(t1), UNBOX(t2)) if (t1 == t2) =>
Some(Nil)
- case (LOAD_FIELD(sym, isStatic), DROP(_)) if !sym.hasAnnotation(definitions.VolatileAttr) =>
- if (isStatic)
- Some(Nil)
- else
- Some(DROP(REFERENCE(definitions.ObjectClass)) :: Nil)
+ case (LOAD_FIELD(sym, /* isStatic */false), DROP(_)) if !sym.hasAnnotation(definitions.VolatileAttr) && inliner.isClosureClass(sym.owner) =>
+ Some(DROP(REFERENCE(definitions.ObjectClass)) :: Nil)
case _ => None
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index 90c37ba0b3..4b419b210c 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -169,9 +169,14 @@ abstract class DeadCodeElimination extends SubComponent {
case RETURN(_) | JUMP(_) | CJUMP(_, _, _, _) | CZJUMP(_, _, _, _) | STORE_FIELD(_, _) |
THROW(_) | LOAD_ARRAY_ITEM(_) | STORE_ARRAY_ITEM(_) | SCOPE_ENTER(_) | SCOPE_EXIT(_) | STORE_THIS(_) |
- LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() | CHECK_CAST(_) =>
+ LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() | CHECK_CAST(_) | CREATE_ARRAY(_, _) =>
moveToWorkList()
+ case LOAD_FIELD(sym, isStatic) if isStatic || !inliner.isClosureClass(sym.owner) =>
+ // static load may trigger static initization.
+ // non-static load can throw NPE (but we know closure fields can't be accessed via a
+ // null reference.
+ moveToWorkList()
case CALL_METHOD(m1, _) if isSideEffecting(m1) =>
moveToWorkList()
@@ -193,6 +198,8 @@ abstract class DeadCodeElimination extends SubComponent {
moveToWorkListIf(necessary)
case LOAD_MODULE(sym) if isLoadNeeded(sym) =>
moveToWorkList() // SI-4859 Module initialization might side-effect.
+ case CALL_PRIMITIVE(Arithmetic(DIV | REM, INT | LONG) | ArrayLength(_)) =>
+ moveToWorkList() // SI-8601 Might divide by zero
case _ => ()
moveToWorkListIf(cond = false)
}
diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
index 8b897b83b2..38a7525862 100644
--- a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
@@ -16,6 +16,7 @@ trait AbsScalaSettings {
type ChoiceSetting <: Setting { type T = String }
type IntSetting <: Setting { type T = Int }
type MultiStringSetting <: Setting { type T = List[String] }
+ type MultiChoiceSetting <: Setting { type T = List[String] }
type PathSetting <: Setting { type T = String }
type PhasesSetting <: Setting { type T = List[String] }
type StringSetting <: Setting { type T = String }
@@ -28,6 +29,7 @@ trait AbsScalaSettings {
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting
def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting
+ def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String]): MultiChoiceSetting
def OutputSetting(outputDirs: OutputDirs, default: String): OutputSetting
def PathSetting(name: String, descr: String, default: String): PathSetting
def PhasesSetting(name: String, descr: String, default: String): PhasesSetting
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index 3590254128..54e444decf 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -211,6 +211,11 @@ class MutableSettings(val errorFn: String => Unit)
add(new ChoiceSetting(name, helpArg, descr, choices, default))
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) = add(new IntSetting(name, descr, default, range, parser))
def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr))
+ def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String]): MultiChoiceSetting = {
+ val fullChoix = choices.mkString(": ", ",", ".")
+ val fullDescr = s"$descr$fullChoix"
+ add(new MultiChoiceSetting(name, helpArg, fullDescr, choices))
+ }
def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default))
def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default))
def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default))
@@ -548,8 +553,16 @@ class MutableSettings(val errorFn: String => Unit)
}
}
+ class MultiChoiceSetting private[nsc](
+ name: String,
+ arg: String,
+ descr: String,
+ override val choices: List[String])
+ extends MultiStringSetting(name, arg, descr)
+
/** A setting that accumulates all strings supplied to it,
- * until it encounters one starting with a '-'. */
+ * until it encounters one starting with a '-'.
+ */
class MultiStringSetting private[nsc](
name: String,
val arg: String,
@@ -558,11 +571,15 @@ class MutableSettings(val errorFn: String => Unit)
type T = List[String]
protected var v: T = Nil
def appendToValue(str: String) { value ++= List(str) }
+ def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'")
def tryToSet(args: List[String]) = {
val (strings, rest) = args span (x => !x.startsWith("-"))
- strings foreach appendToValue
-
+ strings foreach {
+ case "_" if choices.nonEmpty => choices foreach appendToValue
+ case s if choices.isEmpty || (choices contains s) => appendToValue(s)
+ case s => badChoice(s, name)
+ }
Some(rest)
}
override def tryToSetColon(args: List[String]) = tryToSet(args)
@@ -570,6 +587,8 @@ class MutableSettings(val errorFn: String => Unit)
def clear(): Unit = (v = Nil)
def unparse: List[String] = value map (name + ":" + _)
+ def contains(s: String) = value contains s
+
withHelpSyntax(name + ":<" + arg + ">")
}
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index a643a08614..20ccc30ff6 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -62,8 +62,14 @@ trait ScalaSettings extends AbsScalaSettings
/*val argfiles = */ BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)")
val classpath = PathSetting ("-classpath", "Specify where to find user class files.", defaultClasspath) withAbbreviation "-cp"
val d = OutputSetting (outputDirs, ".")
- val nospecialization = BooleanSetting ("-no-specialization", "Ignore @specialize annotations.")
- val language = MultiStringSetting("-language", "feature", "Enable one or more language features.")
+ val nospecialization = BooleanSetting ("-no-specialization", "Ignore @specialize annotations.")
+
+ // Would be nice to build this dynamically from scala.languageFeature.
+ // The two requirements: delay error checking until you have symbols, and let compiler command build option-specific help.
+ val language = {
+ val features = List("dynamics", "postfixOps", "reflectiveCalls", "implicitConversions", "higherKinds", "existentials", "experimental.macros")
+ MultiChoiceSetting("-language", "feature", "Enable one or more language features", features)
+ }
/*
* The previous "-source" option is intended to be used mainly
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 8b739958ff..447fa66ae4 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -251,7 +251,7 @@ abstract class SymbolLoaders {
root.setInfo(new PackageClassInfoType(newScope, root))
if (!root.isRoot) {
- for (classRep <- classpath.classes if platform.doLoad(classRep)) {
+ for (classRep <- classpath.classes) {
initializeFromClassPath(root, classRep)
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index ea600bc586..d7cd92adf2 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -356,9 +356,13 @@ abstract class ClassfileParser {
// SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
// therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
// that are not in their correct place (see bug for details)
- if (!settings.isScaladoc)
- warning(s"Class $name not found - continuing with a stub.")
- return NoSymbol.newClass(name.toTypeName)
+
+ // TODO More consistency with use of stub symbols in `Unpickler`
+ // - better owner than `NoSymbol`
+ // - remove eager warning
+ val msg = s"Class $name not found - continuing with a stub."
+ if (!settings.isScaladoc) warning(msg)
+ return NoSymbol.newStubSymbol(name.toTypeName, msg)
}
val completer = new loaders.ClassfileLoader(file)
var owner: Symbol = rootMirror.RootClass
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
index 1468680fe0..1f8ab7e887 100644
--- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
+++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
@@ -132,7 +132,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
}
val params = ((optionSymbol(thisProxy) map {proxy:Symbol => ValDef(proxy)}) ++ (target.paramss.flatten map ValDef.apply)).toList
- val methSym = oldClass.newMethod(unit.freshTermName(nme.accessor.toString()), target.pos, FINAL | BRIDGE | SYNTHETIC | PROTECTED | STATIC)
+ val methSym = oldClass.newMethod(unit.freshTermName(nme.accessor.toString() + "$"), target.pos, FINAL | BRIDGE | SYNTHETIC | PROTECTED | STATIC)
val paramSyms = params map {param => methSym.newSyntheticValueParam(param.symbol.tpe, param.name) }
@@ -238,7 +238,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
// - reinstate the assertion in `Erasure.resolveAnonymousBridgeClash`
val suffix = "$lambda$" + (
if (funOwner.isPrimaryConstructor) ""
- else "$" + funOwner.name
+ else "$" + funOwner.name + "$"
)
val name = unit.freshTypeName(s"${oldClass.name.decode}$suffix")
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 673bc04bd9..33e8e47c76 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -1004,24 +1004,56 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
buildBitmapOffsets()
var stats1 = addCheckedGetters(clazz, stats)
- def accessedReference(sym: Symbol) = sym.tpe match {
- case MethodType(Nil, ConstantType(c)) => Literal(c)
- case _ =>
- // if it is a mixed-in lazy value, complete the accessor
- if (sym.isLazy && sym.isGetter) {
- val isUnit = sym.tpe.resultType.typeSymbol == UnitClass
- val initCall = Apply(staticRef(initializer(sym)), gen.mkAttributedThis(clazz) :: Nil)
- val selection = Select(This(clazz), sym.accessed)
- val init = if (isUnit) initCall else atPos(sym.pos)(Assign(selection, initCall))
- val returns = if (isUnit) UNIT else selection
-
- mkLazyDef(clazz, sym, List(init), returns, fieldOffset(sym))
- }
- else sym.getter(sym.owner).tpe.resultType.typeSymbol match {
- case UnitClass => UNIT
- case _ => Select(This(clazz), sym.accessed)
- }
+ def getterBody(getter: Symbol) = {
+ assert(getter.isGetter)
+ val readValue = getter.tpe match {
+ // A field "final val f = const" in a trait generates a getter with a ConstantType.
+ case MethodType(Nil, ConstantType(c)) =>
+ Literal(c)
+ case _ =>
+ // if it is a mixed-in lazy value, complete the accessor
+ if (getter.isLazy) {
+ val isUnit = isUnitGetter(getter)
+ val initCall = Apply(staticRef(initializer(getter)), gen.mkAttributedThis(clazz) :: Nil)
+ val selection = fieldAccess(getter)
+ val init = if (isUnit) initCall else atPos(getter.pos)(Assign(selection, initCall))
+ val returns = if (isUnit) UNIT else selection
+ mkLazyDef(clazz, getter, List(init), returns, fieldOffset(getter))
+ }
+ // For a field of type Unit in a trait, no actual field is generated when being mixed in.
+ else if (isUnitGetter(getter)) UNIT
+ else fieldAccess(getter)
+ }
+ if (!needsInitFlag(getter)) readValue
+ else mkCheckedAccessor(clazz, readValue, fieldOffset(getter), getter.pos, getter)
+ }
+
+ def setterBody(setter: Symbol) = {
+ val getter = setter.getterIn(clazz)
+
+ // A trait with a field of type Unit creates a trait setter (invoked by the
+ // implementation class constructor), like for any other trait field.
+ // However, no actual field is created in the class that mixes in the trait.
+ // Therefore the setter does nothing (except setting the -Xcheckinit flag).
+
+ val setInitFlag =
+ if (!needsInitFlag(getter)) Nil
+ else List(mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))
+
+ val fieldInitializer =
+ if (isUnitGetter(getter)) Nil
+ else List(Assign(fieldAccess(setter), Ident(setter.firstParam)))
+
+ (fieldInitializer ::: setInitFlag) match {
+ case Nil => UNIT
+ // If there's only one statement, the Block factory does not actually create a Block.
+ case stats => Block(stats: _*)
+ }
}
+
+ def isUnitGetter(getter: Symbol) = getter.tpe.resultType.typeSymbol == UnitClass
+ def fieldAccess(accessor: Symbol) = Select(This(clazz), accessor.accessed)
+
def isOverriddenSetter(sym: Symbol) =
nme.isTraitSetterName(sym.name) && {
val other = sym.nextOverriddenSymbol
@@ -1036,27 +1068,17 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
// if class is not a trait add accessor definitions
else if (!clazz.isTrait) {
- // This needs to be a def to avoid sharing trees
- def accessedRef = accessedReference(sym)
if (isConcreteAccessor(sym)) {
// add accessor definitions
addDefDef(sym, {
if (sym.isSetter) {
+ // If this is a setter of a mixed-in field which is overridden by another mixin,
+ // the trait setter of the overridden one does not need to do anything - the
+ // trait setter of the overriding field will initialize the field.
if (isOverriddenSetter(sym)) UNIT
- else accessedRef match {
- case ref @ Literal(_) => ref
- case ref =>
- val init = Assign(ref, Ident(sym.firstParam))
- val getter = sym.getter(clazz)
-
- if (!needsInitFlag(getter)) init
- else Block(init, mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)), UNIT)
- }
+ else setterBody(sym)
}
- else if (needsInitFlag(sym))
- mkCheckedAccessor(clazz, accessedRef, fieldOffset(sym), sym.pos, sym)
- else
- accessedRef
+ else getterBody(sym)
})
}
else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) {
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 02e55241b3..908aa69310 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -538,6 +538,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
bytecodeClazz.info
val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE)
+ sClass.setAnnotations(clazz.annotations) // SI-8574 important that the subclass picks up @SerialVersionUID, @strictfp, etc.
def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long, newName: Name = null) =
member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED), newName)
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
index 2893cbdf45..894f959319 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
@@ -149,14 +149,15 @@ trait TreeAndTypeAnalysis extends Debugging {
object typeArgsToWildcardsExceptArray extends TypeMap {
// SI-6771 dealias would be enough today, but future proofing with the dealiasWiden.
// See neg/t6771b.scala for elaboration
- def apply(tp: Type): Type = tp.dealiasWiden match {
+ def apply(tp: Type): Type = tp.dealias match {
case TypeRef(pre, sym, args) if args.nonEmpty && (sym ne ArrayClass) =>
TypeRef(pre, sym, args map (_ => WildcardType))
case _ =>
mapOver(tp)
}
}
- debug.patmatResult(s"checkableType($tp)")(typeArgsToWildcardsExceptArray(tp))
+ val result = typeArgsToWildcardsExceptArray(tp)
+ debug.patmatResult(s"checkableType($tp)")(result)
}
// a type is "uncheckable" (for exhaustivity) if we don't statically know its subtypes (i.e., it's unsealed)
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala
index 1902606d86..31b1ffa912 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala
@@ -29,8 +29,12 @@ trait Solving extends Logic {
type Clause = collection.Set[Lit]
// a clause is a disjunction of distinct literals
def clause(l: Lit*): Clause = (
- // neg/t7020.scala changes output 1% of the time, the non-determinism is quelled with this linked set
- mutable.LinkedHashSet(l: _*)
+ if (l.lengthCompare(1) <= 0) {
+ l.toSet // SI-8531 Avoid LinkedHashSet's bulk for 0 and 1 element clauses
+ } else {
+ // neg/t7020.scala changes output 1% of the time, the non-determinism is quelled with this linked set
+ mutable.LinkedHashSet(l: _*)
+ }
)
type Lit
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index d87090fa46..73c3e6f016 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1306,7 +1306,7 @@ trait Implicits {
}
def wrapResult(tree: Tree): SearchResult =
- if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter, Nil)
+ if (tree == EmptyTree) SearchFailure else new SearchResult(atPos(pos.focus)(tree), EmptyTreeTypeSubstituter, Nil)
/** Materializes implicits of predefined types (currently, manifests and tags).
* Will be replaced by implicit macros once we fix them.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 9cf92ca5b9..f4456998c0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -42,7 +42,7 @@ import Fingerprint._
* (Expr(elems))
* (TypeTag(Int))
*/
-trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
+trait Macros extends MacroRuntimes with Traces with Helpers {
self: Analyzer =>
import global._
@@ -50,6 +50,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
import treeInfo.{isRepeatedParamType => _, _}
import MacrosStats._
+ lazy val fastTrack = new FastTrack[self.type](self)
+
def globalSettings = global.settings
protected def findMacroClassLoader(): ClassLoader = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 23dc57d5b9..099031d536 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -711,10 +711,7 @@ trait Namers extends MethodSynthesis {
val m = ensureCompanionObject(tree, caseModuleDef)
m.moduleClass.updateAttachment(new ClassForCaseCompanionAttachment(tree))
}
- val hasDefault = impl.body exists {
- case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => mexists(vparamss)(_.mods.hasDefault)
- case _ => false
- }
+ val hasDefault = impl.body exists treeInfo.isConstructorWithDefault
if (hasDefault) {
val m = ensureCompanionObject(tree)
m.updateAttachment(new ConstructorDefaultsAttachment(tree, null))
@@ -1043,10 +1040,10 @@ trait Namers extends MethodSynthesis {
* so the resulting type is a valid external method type, it does not contain (references to) skolems.
*/
def thisMethodType(restpe: Type) = {
- val checkDependencies = new DependentTypeChecker(context)(this)
- checkDependencies check vparamSymss
- // DEPMETTODO: check not needed when they become on by default
- checkDependencies(restpe)
+ if (vparamSymss.lengthCompare(0) > 0) { // OPT fast path for methods of 0-1 parameter lists
+ val checkDependencies = new DependentTypeChecker(context)(this)
+ checkDependencies check vparamSymss
+ }
val makeMethodType = (vparams: List[Symbol], restpe: Type) => {
// TODODEPMET: check that we actually don't need to do anything here
@@ -1180,7 +1177,13 @@ trait Namers extends MethodSynthesis {
}
}
- addDefaultGetters(meth, ddef, vparamss, tparams, overriddenSymbol(methResTp))
+ val overridden = {
+ val isConstr = meth.isConstructor
+ if (isConstr || !methOwner.isClass) NoSymbol else overriddenSymbol(methResTp)
+ }
+ val hasDefaults = mexists(vparamss)(_.symbol.hasDefault) || mexists(overridden.paramss)(_.hasDefault)
+ if (hasDefaults)
+ addDefaultGetters(meth, ddef, vparamss, tparams, overridden)
// fast track macros, i.e. macros defined inside the compiler, are hardcoded
// hence we make use of that and let them have whatever right-hand side they need
@@ -1222,7 +1225,7 @@ trait Namers extends MethodSynthesis {
* typechecked, the corresponding param would not yet have the "defaultparam"
* flag.
*/
- private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overriddenSymbol: => Symbol) {
+ private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overridden: Symbol) {
val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetAttrs(ddef.duplicate)
// having defs here is important to make sure that there's no sneaky tree sharing
// in methods with multiple default parameters
@@ -1230,7 +1233,6 @@ trait Namers extends MethodSynthesis {
def rvparamss = rvparamss0.map(_.map(_.duplicate))
val methOwner = meth.owner
val isConstr = meth.isConstructor
- val overridden = if (isConstr || !methOwner.isClass) NoSymbol else overriddenSymbol
val overrides = overridden != NoSymbol && !overridden.isOverloaded
// value parameters of the base class (whose defaults might be overridden)
var baseParamss = (vparamss, overridden.tpe.paramss) match {
@@ -1748,7 +1750,6 @@ trait Namers extends MethodSynthesis {
for (p <- vps)
this(p.info)
// can only refer to symbols in earlier parameter sections
- // (if the extension is enabled)
okParams ++= vps
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index b166bf988d..4540017b62 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -132,7 +132,16 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
defaultMethodNames.toList.distinct foreach { name =>
val methods = clazz.info.findMember(name, 0L, requiredFlags = METHOD, stableOnly = false).alternatives
- val haveDefaults = methods filter (sym => mexists(sym.info.paramss)(_.hasDefault) && !nme.isProtectedAccessorName(sym.name))
+ def hasDefaultParam(tpe: Type): Boolean = tpe match {
+ case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe)
+ case _ => false
+ }
+ val haveDefaults = methods filter (
+ if (settings.isScala211)
+ (sym => mexists(sym.info.paramss)(_.hasDefault) && !nme.isProtectedAccessorName(sym.name))
+ else
+ (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name))
+ )
if (haveDefaults.lengthCompare(1) > 0) {
val owners = haveDefaults map (_.owner)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 3690750e42..66b1c2d87a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -741,7 +741,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val featureName = (nestedOwners map (_.name + ".")).mkString + featureTrait.name
def action(): Boolean = {
def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, reportAmbiguous = true, isView = false, context).isSuccess
- def hasOption = settings.language.value exists (s => s == featureName || s == "_")
+ def hasOption = settings.language contains featureName
val OK = hasImport || hasOption
if (!OK) {
val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) =
@@ -1687,7 +1687,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val sameSourceFile = context.unit.source.file == psym.sourceFile
- if (psym.hasDeprecatedInheritanceAnnotation && !sameSourceFile) {
+ if (!isPastTyper && psym.hasDeprecatedInheritanceAnnotation && !sameSourceFile) {
val suffix = psym.deprecatedInheritanceMessage map (": " + _) getOrElse ""
val msg = s"inheritance from ${psym.fullLocationString} is deprecated$suffix"
unit.deprecationWarning(parent.pos, msg)
@@ -3022,7 +3022,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
|| (looker.hasAccessorFlag && !accessed.hasAccessorFlag && accessed.isPrivate)
)
- def checkNoDoubleDefs(stats: List[Tree]): Unit = {
+ def checkNoDoubleDefs: Unit = {
val scope = if (inBlock) context.scope else context.owner.info.decls
var e = scope.elems
while ((e ne null) && e.owner == scope) {
@@ -3057,8 +3057,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// the corresponding synthetics to the package class, only to the package object class.
def shouldAdd(sym: Symbol) =
inBlock || !context.isInPackageObject(sym, context.owner)
- for (sym <- scope if shouldAdd(sym))
- for (tree <- context.unit.synthetics get sym) {
+ for (sym <- scope)
+ for (tree <- context.unit.synthetics get sym if shouldAdd(sym)) { // OPT: shouldAdd is usually true. Call it here, rather than in the outer loop
newStats += typedStat(tree) // might add even more synthetics to the scope
context.unit.synthetics -= sym
}
@@ -3104,7 +3104,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val stats1 = stats mapConserve typedStat
if (phase.erasedTypes) stats1
else {
- checkNoDoubleDefs(stats1)
+ // As packages are open, it doesn't make sense to check double definitions here. Furthermore,
+ // it is expensive if the package is large. Instead, such double defininitions are checked in `Namers.enterInScope`
+ if (!context.owner.isPackageClass)
+ checkNoDoubleDefs
addSynthetics(stats1)
}
}
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
index 8630ecf69e..64cf3d0847 100644
--- a/src/compiler/scala/tools/reflect/FastTrack.scala
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -10,14 +10,18 @@ import scala.tools.reflect.quasiquotes.{ Quasiquotes => QuasiquoteImpls }
/** Optimizes system macro expansions by hardwiring them directly to their implementations
* bypassing standard reflective load and invoke to avoid the overhead of Java/Scala reflection.
*/
-trait FastTrack {
- self: Macros with Analyzer =>
+class FastTrack[MacrosAndAnalyzer <: Macros with Analyzer](val macros: MacrosAndAnalyzer) {
+ import macros._
import global._
import definitions._
import scala.language.implicitConversions
import treeInfo.Applied
+ def contains(symbol: Symbol): Boolean = fastTrackCache().contains(symbol)
+ def apply(symbol: Symbol): FastTrackEntry = fastTrackCache().apply(symbol)
+ def get(symbol: Symbol): Option[FastTrackEntry] = fastTrackCache().get(symbol)
+
private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } =
new { val c: c0.type = c0 } with Taggers
private implicit def context2macroimplementations(c0: MacroContext): FormatInterpolator { val c: c0.type } =
@@ -39,7 +43,6 @@ trait FastTrack {
}
/** A map from a set of pre-established macro symbols to their implementations. */
- def fastTrack: Map[Symbol, FastTrackEntry] = fastTrackCache()
private val fastTrackCache = perRunCaches.newGeneric[Map[Symbol, FastTrackEntry]] {
val runDefinitions = currentRun.runDefinitions
import runDefinitions._
diff --git a/src/eclipse/partest/.classpath b/src/eclipse/partest/.classpath
index c2aab19f18..7f28868d95 100644
--- a/src/eclipse/partest/.classpath
+++ b/src/eclipse/partest/.classpath
@@ -4,11 +4,11 @@
<classpathentry combineaccessrules="false" kind="src" path="/asm"/>
<classpathentry combineaccessrules="false" kind="src" path="/repl"/>
<classpathentry kind="var" path="M2_REPO/com/googlecode/java-diff-utils/diffutils/1.3.0/diffutils-1.3.0.jar"/>
- <classpathentry kind="var" path="M2_REPO/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar"/>
<classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.11.0-M7/1.0.0-RC8/scala-partest_2.11.0-M7-1.0.0-RC8.jar"/>
<classpathentry kind="var" path="SCALA_BASEDIR/lib/ant/ant.jar"/>
- <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
- <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_COMPILER_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
<classpathentry kind="output" path="build-quick-partest-extras"/>
</classpath>
diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala
index cd928a2b61..c0468e8b02 100644
--- a/src/library/scala/StringContext.scala
+++ b/src/library/scala/StringContext.scala
@@ -8,6 +8,9 @@
package scala
+import java.lang.{ StringBuilder => JLSBuilder }
+import scala.annotation.tailrec
+
/** This class provides the basic mechanism to do String Interpolation.
* String Interpolation allows users
* to embed variable references directly in *processed* string literals.
@@ -41,7 +44,7 @@ package scala
* val x: JSONObject = json"{ a: $a }"
* }}}
*
- * Here the `JsonHelper` extenion class implicitly adds the `json` method to
+ * Here the `JsonHelper` extension class implicitly adds the `json` method to
* `StringContext` which can be used for `json` string literals.
*
* @since 2.10.0
@@ -118,7 +121,7 @@ case class StringContext(parts: String*) {
checkLengths(args)
val pi = parts.iterator
val ai = args.iterator
- val bldr = new java.lang.StringBuilder(process(pi.next()))
+ val bldr = new JLSBuilder(process(pi.next()))
while (ai.hasNext) {
bldr append ai.next
bldr append process(pi.next())
@@ -186,60 +189,60 @@ object StringContext {
*/
def treatEscapes(str: String): String = treatEscapes0(str, strict = false)
+ /** Treats escapes, but disallows octal escape sequences. */
def processEscapes(str: String): String = treatEscapes0(str, strict = true)
private def treatEscapes0(str: String, strict: Boolean): String = {
- lazy val bldr = new java.lang.StringBuilder
val len = str.length
- var start = 0
- var cur = 0
- var idx = 0
- def output(ch: Char) = {
- bldr.append(str, start, cur)
- bldr append ch
- start = idx
- }
- while (idx < len) {
- cur = idx
- if (str(idx) == '\\') {
- idx += 1
- if (idx >= len) throw new InvalidEscapeException(str, cur)
- if ('0' <= str(idx) && str(idx) <= '7') {
- if (strict) throw new InvalidEscapeException(str, cur)
- val leadch = str(idx)
- var oct = leadch - '0'
- idx += 1
- if (idx < len && '0' <= str(idx) && str(idx) <= '7') {
- oct = oct * 8 + str(idx) - '0'
- idx += 1
- if (idx < len && leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') {
- oct = oct * 8 + str(idx) - '0'
+ // replace escapes with given first escape
+ def replace(first: Int): String = {
+ val b = new JLSBuilder
+ // append replacement starting at index `i`, with `next` backslash
+ @tailrec def loop(i: Int, next: Int): String = {
+ if (next >= 0) {
+ //require(str(next) == '\\')
+ if (next > i) b.append(str, i, next)
+ var idx = next + 1
+ if (idx >= len) throw new InvalidEscapeException(str, next)
+ val c = str(idx) match {
+ case 'b' => '\b'
+ case 't' => '\t'
+ case 'n' => '\n'
+ case 'f' => '\f'
+ case 'r' => '\r'
+ case '"' => '"'
+ case '\'' => '\''
+ case '\\' => '\\'
+ case o if '0' <= o && o <= '7' =>
+ if (strict) throw new InvalidEscapeException(str, next)
+ val leadch = str(idx)
+ var oct = leadch - '0'
idx += 1
- }
+ if (idx < len && '0' <= str(idx) && str(idx) <= '7') {
+ oct = oct * 8 + str(idx) - '0'
+ idx += 1
+ if (idx < len && leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') {
+ oct = oct * 8 + str(idx) - '0'
+ idx += 1
+ }
+ }
+ idx -= 1 // retreat
+ oct.toChar
+ case _ => throw new InvalidEscapeException(str, next)
}
- output(oct.toChar)
+ idx += 1 // advance
+ b append c
+ loop(idx, str.indexOf('\\', idx))
} else {
- val ch = str(idx)
- idx += 1
- output {
- ch match {
- case 'b' => '\b'
- case 't' => '\t'
- case 'n' => '\n'
- case 'f' => '\f'
- case 'r' => '\r'
- case '\"' => '\"'
- case '\'' => '\''
- case '\\' => '\\'
- case _ => throw new InvalidEscapeException(str, cur)
- }
- }
+ if (i < len) b.append(str, i, len)
+ b.toString
}
- } else {
- idx += 1
}
+ loop(0, first)
+ }
+ str indexOf '\\' match {
+ case -1 => str
+ case i => replace(i)
}
- if (start == 0) str
- else bldr.append(str, start, idx).toString
}
}
diff --git a/src/library/scala/collection/LinearSeq.scala b/src/library/scala/collection/LinearSeq.scala
index 1e4975a0a7..49fbb902ab 100644
--- a/src/library/scala/collection/LinearSeq.scala
+++ b/src/library/scala/collection/LinearSeq.scala
@@ -25,7 +25,7 @@ trait LinearSeq[+A] extends Seq[A]
}
/** $factoryInfo
- * The current default implementation of a $Coll is a `Vector`.
+ * The current default implementation of a $Coll is a `List`.
* @define coll linear sequence
* @define Coll `LinearSeq`
*/
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index b60ea86ab0..d3a7db6968 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -345,8 +345,8 @@ trait TraversableLike[+A, +Repr] extends Any
* $mayNotTerminateInf
*
* @param p the predicate used to test elements.
- * @return `true` if the given predicate `p` holds for all elements
- * of this $coll, otherwise `false`.
+ * @return `true` if this $coll is empty, otherwise `true` if the given predicate `p`
+ * holds for all elements of this $coll, otherwise `false`.
*/
def forall(p: A => Boolean): Boolean = {
var result = true
@@ -362,8 +362,8 @@ trait TraversableLike[+A, +Repr] extends Any
* $mayNotTerminateInf
*
* @param p the predicate used to test elements.
- * @return `true` if the given predicate `p` holds for some of the
- * elements of this $coll, otherwise `false`.
+ * @return `false` if this $coll is empty, otherwise `true` if the given predicate `p`
+ * holds for some of the elements of this $coll, otherwise `false`
*/
def exists(p: A => Boolean): Boolean = {
var result = false
diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala
index 072fd3da44..a8c4e047ab 100644
--- a/src/library/scala/collection/TraversableOnce.scala
+++ b/src/library/scala/collection/TraversableOnce.scala
@@ -85,10 +85,9 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
*/
def seq: TraversableOnce[A]
- /** Presently these are abstract because the Traversable versions use
- * breakable/break, and I wasn't sure enough of how that's supposed to
- * function to consolidate them with the Iterator versions.
- */
+ // Presently these are abstract because the Traversable versions use
+ // breakable/break, and I wasn't sure enough of how that's supposed to
+ // function to consolidate them with the Iterator versions.
def forall(p: A => Boolean): Boolean
def exists(p: A => Boolean): Boolean
def find(p: A => Boolean): Option[A]
diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala
index 14ae57c43a..7d1d6b3781 100644
--- a/src/library/scala/collection/convert/Wrappers.scala
+++ b/src/library/scala/collection/convert/Wrappers.scala
@@ -194,7 +194,7 @@ private[collection] trait Wrappers {
def getKey = k
def getValue = v
def setValue(v1 : B) = self.put(k, v1)
- override def hashCode = byteswap32(k.hashCode) + (byteswap32(v.hashCode) << 16)
+ override def hashCode = byteswap32(k.##) + (byteswap32(v.##) << 16)
override def equals(other: Any) = other match {
case e: ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue
case _ => false
diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala
index 803c980058..2f7643bccf 100644
--- a/src/library/scala/reflect/Manifest.scala
+++ b/src/library/scala/reflect/Manifest.scala
@@ -64,6 +64,7 @@ trait Manifest[T] extends ClassManifest[T] with Equals {
// TODO undeprecated until Scala reflection becomes non-experimental
// @deprecated("Use type tags and manually check the corresponding class or type instead", "2.10.0")
+@SerialVersionUID(1L)
abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals {
override def <:<(that: ClassManifest[_]): Boolean =
(that eq this) || (that eq Manifest.Any) || (that eq Manifest.AnyVal)
@@ -72,6 +73,7 @@ abstract class AnyValManifest[T <: AnyVal](override val toString: String) extend
case _ => false
}
override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
+ @transient
override val hashCode = System.identityHashCode(this)
}
@@ -228,6 +230,7 @@ object ManifestFactory {
private abstract class PhantomManifest[T](_runtimeClass: Predef.Class[_],
override val toString: String) extends ClassTypeManifest[T](None, _runtimeClass, Nil) {
override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
+ @transient
override val hashCode = System.identityHashCode(this)
}
diff --git a/src/partest-extras/scala/tools/partest/BytecodeTest.scala b/src/partest-extras/scala/tools/partest/BytecodeTest.scala
index 7650a892fd..1e4362fcde 100644
--- a/src/partest-extras/scala/tools/partest/BytecodeTest.scala
+++ b/src/partest-extras/scala/tools/partest/BytecodeTest.scala
@@ -34,7 +34,7 @@ abstract class BytecodeTest extends ASMConverters {
/** produce the output to be compared against a checkfile */
protected def show(): Unit
- def main(args: Array[String]): Unit = show
+ def main(args: Array[String]): Unit = show()
// asserts
def sameBytecode(methA: MethodNode, methB: MethodNode) = {
diff --git a/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java
index b1b100fbb0..d97756c171 100644
--- a/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java
+++ b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java
@@ -50,7 +50,7 @@ public class ProfilerVisitor extends ClassVisitor implements Opcodes {
mv.visitLdcInsn(name);
mv.visitLdcInsn(desc);
mv.visitMethodInsn(INVOKESTATIC, profilerClass, "methodCalled",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", false);
}
}
return mv;
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 19e9eef851..f814a746f5 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -302,7 +302,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
*/
def defaultTargets = symbol.annotations map (_.symbol) filter isMetaAnnotation
// Test whether the typeSymbol of atp conforms to the given class.
- def matches(clazz: Symbol) = symbol isNonBottomSubClass clazz
+ def matches(clazz: Symbol) = !symbol.isInstanceOf[StubSymbol] && (symbol isNonBottomSubClass clazz)
// All subtrees of all args are considered.
def hasArgWhich(p: Tree => Boolean) = args exists (_ exists p)
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index cf3f356daa..103f885ad4 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -48,22 +48,17 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
* This is necessary because when run from reflection every scope needs to have a
* SynchronizedScope as mixin.
*/
- class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeApi with MemberScopeApi {
+ class Scope protected[Scopes]() extends ScopeApi with MemberScopeApi {
- protected[Scopes] def this(base: Scope) = {
- this(base.elems)
- nestinglevel = base.nestinglevel + 1
- }
-
- private[scala] var elems: ScopeEntry = initElems
+ private[scala] var elems: ScopeEntry = _
/** The number of times this scope is nested in another
*/
- private var nestinglevel = 0
+ private[Scopes] var nestinglevel = 0
/** the hash table
*/
- private var hashtable: Array[ScopeEntry] = null
+ private[Scopes] var hashtable: Array[ScopeEntry] = null
/** a cache for all elements, to be used by symbol iterator.
*/
@@ -84,8 +79,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
private val MIN_HASH = 8
- if (size >= MIN_HASH) createHash()
-
/** Returns a new scope with the same content as this one. */
def cloneScope: Scope = newScopeWith(this.toList: _*)
@@ -435,7 +428,14 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
/** Create a new scope nested in another one with which it shares its elements */
- def newNestedScope(outer: Scope): Scope = new Scope(outer)
+ final def newNestedScope(outer: Scope): Scope = {
+ val nested = newScope // not `new Scope`, we must allow the runtime reflection universe to mixin SynchronizedScopes!
+ nested.elems = outer.elems
+ nested.nestinglevel = outer.nestinglevel + 1
+ if (outer.hashtable ne null)
+ nested.hashtable = java.util.Arrays.copyOf(outer.hashtable, outer.hashtable.length)
+ nested
+ }
/** Create a new scope with given initial elements */
def newScopeWith(elems: Symbol*): Scope = {
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 7cf749c048..b7d7d4df88 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -51,6 +51,11 @@ abstract class TreeInfo {
case _ => false
}
+ def isConstructorWithDefault(t: Tree) = t match {
+ case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => mexists(vparamss)(_.mods.hasDefault)
+ case _ => false
+ }
+
/** Is tree a pure (i.e. non-side-effecting) definition?
*/
def isPureDef(tree: Tree): Boolean = tree match {
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index f5bddb1784..6584d80de3 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -760,8 +760,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass)
}
- def enter(sym: Symbol, mods: JavaAccFlags) =
- ( if (mods.isStatic) module.moduleClass else clazz ).info.decls enter sym
+ def enter(sym: Symbol, mods: JavaAccFlags) = followStatic(clazz, module, mods).info.decls enter sym
def enterEmptyCtorIfNecessary(): Unit = {
if (jclazz.getConstructors.isEmpty)
@@ -801,8 +800,12 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
* If Java modifiers `mods` contain STATIC, return the module class
* of the companion module of `clazz`, otherwise the class `clazz` itself.
*/
- private def followStatic(clazz: Symbol, mods: JavaAccFlags) =
- if (mods.isStatic) clazz.companionModule.moduleClass else clazz
+ private def followStatic(clazz: Symbol, mods: JavaAccFlags): Symbol = followStatic(clazz, clazz.companionModule, mods)
+
+ private def followStatic(clazz: Symbol, module: Symbol, mods: JavaAccFlags): Symbol =
+ // SI-8196 `orElse(clazz)` needed for implementation details of the backend, such as the static
+ // field containing the cache for structural calls.
+ if (mods.isStatic) module.moduleClass.orElse(clazz) else clazz
/** Methods which need to be treated with care
* because they either are getSimpleName or call getSimpleName:
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index c56bc28d90..7ba68b8733 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -91,7 +91,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
//
// Short of significantly changing SymbolLoaders I see no other way than just
// to slap a global lock on materialization in runtime reflection.
- class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand
+ class PackageScope(pkgClass: Symbol) extends Scope
with SynchronizedScope {
assert(pkgClass.isType)
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
index c90901410a..4a8585d616 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -37,8 +37,7 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
// Scopes
- override def newScope = new Scope() with SynchronizedScope
- override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope
+ override def newScope = new Scope with SynchronizedScope
trait SynchronizedScope extends Scope {
// we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
index 55fb370a41..3e352a95b3 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/index.css
@@ -310,6 +310,7 @@ h1 {
position: fixed;
margin-left: 300px;
display: block;
+ -webkit-overflow-scrolling: touch;
}
#content > iframe {
diff --git a/test/files/jvm/beanInfo.check b/test/files/jvm/beanInfo.check
new file mode 100644
index 0000000000..d74e127711
--- /dev/null
+++ b/test/files/jvm/beanInfo.check
@@ -0,0 +1,6 @@
+property descriptors
+x -- int -- public int p.C.x() -- null
+y -- class java.lang.String -- public java.lang.String p.C.y() -- public void p.C.y_$eq(java.lang.String)
+z -- class scala.collection.immutable.List -- public scala.collection.immutable.List p.C.z() -- public void p.C.z_$eq(scala.collection.immutable.List)
+method descriptors
+f -- public p.C p.C.f()
diff --git a/test/files/jvm/beanInfo/C_1.scala b/test/files/jvm/beanInfo/C_1.scala
new file mode 100644
index 0000000000..a338abea1d
--- /dev/null
+++ b/test/files/jvm/beanInfo/C_1.scala
@@ -0,0 +1,9 @@
+package p
+
+@scala.beans.BeanInfo
+class C {
+ val x: Int = 0
+ var y: String = ""
+ var z: List[_] = Nil
+ def f: C = ???
+}
diff --git a/test/files/jvm/beanInfo/Test_2.scala b/test/files/jvm/beanInfo/Test_2.scala
new file mode 100644
index 0000000000..fa9b6e1391
--- /dev/null
+++ b/test/files/jvm/beanInfo/Test_2.scala
@@ -0,0 +1,17 @@
+object Test extends App {
+ val info = java.beans.Introspector.getBeanInfo(classOf[p.C])
+
+ println("property descriptors")
+
+ val pds = info.getPropertyDescriptors
+ for (pd <- pds) {
+ println(s"${pd.getName} -- ${pd.getPropertyType} -- ${pd.getReadMethod} -- ${pd.getWriteMethod}")
+ }
+
+ println("method descriptors")
+
+ val mds = info.getMethodDescriptors
+ for (md <- mds) {
+ println(s"${md.getName} -- ${md.getMethod}")
+ }
+}
diff --git a/test/files/jvm/t8582.check b/test/files/jvm/t8582.check
new file mode 100644
index 0000000000..564f482ff8
--- /dev/null
+++ b/test/files/jvm/t8582.check
@@ -0,0 +1,44 @@
+getClass on module gives module class
+ class p1.p2.Singleton$Singleton$
+
+Nested module classes are found through reflection
+ p1.p2.Singleton$Singleton$: List(class p1.p2.Singleton$Singleton$Singleton$)
+
+Reflection can find direct nested classes (A1-B1-C1)
+ A1: List(class A1$B1)
+ A1$B1: List(class A1$B1$C1)
+ A1$B1$C1: List()
+
+Reflection can find direct nested classes (A2-B2-C2)
+ A2: List(class A2$B2)
+ A2$B2: List(class A2$B2$C2)
+ A2$B2$C2: List()
+
+Mirror classes have the same InnerClass attributes as the corresponding module class:
+ className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9]
+Module class
+ className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9]
+
+An outer class has a InnerClass attribute for direct nested classes
+ className[A1$B1] outerClassName[A1] innerName[B1] access[1]
+A nested class has an InnerClass attribute for itself (and also for its nested classes)
+ className[A1$B1] outerClassName[A1] innerName[B1] access[1]
+ className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1]
+C1 is a nested class, so it has an InnerClass attribute for itself.
+Because that attribute leads to an entry for B1 in the constant pool, C1 needs an InnerClass attribute for B1.
+ className[A1$B1] outerClassName[A1] innerName[B1] access[1]
+ className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1]
+
+The BeanInfo class has the same InnerClass attributes as the corresponding bean
+ className[A1$B1] outerClassName[A1] innerName[B1] access[1]
+ className[A1$B1$C1] outerClassName[A1$B1] innerName[C1] access[1]
+
+Class A2 mentions class C2 in the constant pool (due to method f), therefore it needs an InnerClass attribute for C1
+ className[A2$B2] outerClassName[A2] innerName[B2] access[1]
+ className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1]
+B2
+ className[A2$B2] outerClassName[A2] innerName[B2] access[1]
+ className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1]
+C2
+ className[A2$B2] outerClassName[A2] innerName[B2] access[1]
+ className[A2$B2$C2] outerClassName[A2$B2] innerName[C2] access[1]
diff --git a/test/files/jvm/t8582.scala b/test/files/jvm/t8582.scala
new file mode 100644
index 0000000000..8a57ef7952
--- /dev/null
+++ b/test/files/jvm/t8582.scala
@@ -0,0 +1,81 @@
+import scala.tools.partest.BytecodeTest
+import scala.collection.JavaConverters._
+
+package p1 {
+ package p2 {
+ object Singleton {
+ object Singleton {
+ object Singleton
+ }
+ }
+ }
+}
+
+class A1 {
+ class B1 {
+ @scala.beans.BeanInfo
+ class C1
+ }
+}
+
+class A2 {
+ class B2 {
+ class C2
+ }
+ def f: B2#C2 = null
+}
+
+
+object Test extends BytecodeTest {
+ import p1.p2._
+
+ def nested(c: Class[_]) = s" ${c.getName}: ${c.getDeclaredClasses.toList}"
+
+ def nprintln(s: String) = println("\n"+s)
+ def printInner(cname: String): Unit = {
+ val cnode = loadClassNode(cname)
+ println(cnode.innerClasses.asScala.toList.map(i => s"className[${i.name}] outerClassName[${i.outerName}] innerName[${i.innerName}] access[${i.access}]").mkString(" ", "\n ", ""))
+ }
+
+ def show() {
+
+ println("getClass on module gives module class")
+ println(" " + Singleton.Singleton.getClass)
+
+ nprintln("Nested module classes are found through reflection")
+ println(nested(Singleton.Singleton.getClass))
+
+ nprintln("Reflection can find direct nested classes (A1-B1-C1)")
+ println(nested(classOf[A1]))
+ println(nested(classOf[A1#B1]))
+ println(nested(classOf[A1#B1#C1]))
+
+ nprintln("Reflection can find direct nested classes (A2-B2-C2)")
+ println(nested(classOf[A2]))
+ println(nested(classOf[A2#B2]))
+ println(nested(classOf[A2#B2#C2]))
+
+ nprintln("Mirror classes have the same InnerClass attributes as the corresponding module class:")
+ printInner("p1.p2.Singleton") // mirror class
+ println("Module class")
+ printInner("p1.p2.Singleton$")
+
+ nprintln("An outer class has a InnerClass attribute for direct nested classes")
+ printInner("A1")
+ println("A nested class has an InnerClass attribute for itself (and also for its nested classes)")
+ printInner("A1$B1")
+ println("C1 is a nested class, so it has an InnerClass attribute for itself.\n"+
+ "Because that attribute leads to an entry for B1 in the constant pool, C1 needs an InnerClass attribute for B1.")
+ printInner("A1$B1$C1")
+
+ nprintln("The BeanInfo class has the same InnerClass attributes as the corresponding bean")
+ printInner("A1$B1$C1BeanInfo")
+
+ nprintln("Class A2 mentions class C2 in the constant pool (due to method f), therefore it needs an InnerClass attribute for C1")
+ printInner("A2")
+ println("B2")
+ printInner("A2$B2")
+ println("C2")
+ printInner("A2$B2$C2")
+ }
+}
diff --git a/test/files/jvm/unreachable.flags b/test/files/jvm/unreachable.flags
new file mode 100644
index 0000000000..49f2d2c4c8
--- /dev/null
+++ b/test/files/jvm/unreachable.flags
@@ -0,0 +1 @@
+-Ybackend:GenASM
diff --git a/test/files/neg/double-def-top-level.check b/test/files/neg/double-def-top-level.check
new file mode 100644
index 0000000000..85b16e81e5
--- /dev/null
+++ b/test/files/neg/double-def-top-level.check
@@ -0,0 +1,7 @@
+D_3.scala:1: error: C is already defined as class C
+class C
+ ^
+D_3.scala:2: error: O is already defined as object O
+object O
+ ^
+two errors found
diff --git a/test/files/neg/double-def-top-level/A_1.scala b/test/files/neg/double-def-top-level/A_1.scala
new file mode 100644
index 0000000000..c3d68d9d05
--- /dev/null
+++ b/test/files/neg/double-def-top-level/A_1.scala
@@ -0,0 +1,4 @@
+package p
+
+class C
+object O
diff --git a/test/files/neg/double-def-top-level/B_2.scala b/test/files/neg/double-def-top-level/B_2.scala
new file mode 100644
index 0000000000..c328e8c964
--- /dev/null
+++ b/test/files/neg/double-def-top-level/B_2.scala
@@ -0,0 +1,2 @@
+class C /* noerror */
+object O /* noerror */ \ No newline at end of file
diff --git a/test/files/neg/double-def-top-level/C_3.scala b/test/files/neg/double-def-top-level/C_3.scala
new file mode 100644
index 0000000000..e1c327c15a
--- /dev/null
+++ b/test/files/neg/double-def-top-level/C_3.scala
@@ -0,0 +1,2 @@
+class C
+object O \ No newline at end of file
diff --git a/test/files/neg/double-def-top-level/D_3.scala b/test/files/neg/double-def-top-level/D_3.scala
new file mode 100644
index 0000000000..518e0d1c54
--- /dev/null
+++ b/test/files/neg/double-def-top-level/D_3.scala
@@ -0,0 +1,2 @@
+class C
+object O
diff --git a/test/files/neg/t6162-inheritance.check b/test/files/neg/t6162-inheritance.check
index 13c78030d9..c9f4ddaec1 100644
--- a/test/files/neg/t6162-inheritance.check
+++ b/test/files/neg/t6162-inheritance.check
@@ -7,12 +7,6 @@ object SubT extends T
usage.scala:8: warning: inheritance from trait S in package t6126 is deprecated
new S {
^
-usage.scala:3: warning: inheritance from class Foo in package t6126 is deprecated: `Foo` will be made final in a future version.
-class SubFoo extends Foo
- ^
-usage.scala:5: warning: inheritance from trait T in package t6126 is deprecated
-object SubT extends T
- ^
error: No warnings can be incurred under -Xfatal-warnings.
-5 warnings found
+three warnings found
one error found
diff --git a/test/files/neg/t6771b.check b/test/files/neg/t6771b.check
index ba99e9178d..0c9fae533e 100644
--- a/test/files/neg/t6771b.check
+++ b/test/files/neg/t6771b.check
@@ -1,4 +1,4 @@
-t6771b.scala:14: error: type mismatch;
+t6771b.scala:12: error: type mismatch;
found : x.type (with underlying type String)
required: Test.a.type
b = b match { case x => x }
diff --git a/test/files/neg/t6771b.scala b/test/files/neg/t6771b.scala
index 78f11f7750..9723f70290 100644
--- a/test/files/neg/t6771b.scala
+++ b/test/files/neg/t6771b.scala
@@ -6,8 +6,6 @@
// But, to the intrepid hacker who works on this, a few notes:
// You'll have to look into places in the pattern matcher that
// call `dealias`, and see if they need to be `dealiasWiden`.
-// For example, if `checkableType` used only `dealias`, `pos/t6671.scala`
-// would fail.
object Test {
val a = ""; var b: a.type = a
diff --git a/test/files/neg/t6988.check b/test/files/neg/t6988.check
new file mode 100644
index 0000000000..acb7b3cb08
--- /dev/null
+++ b/test/files/neg/t6988.check
@@ -0,0 +1,7 @@
+t6988.scala:3: error: annotation argument needs to be a constant; found: 13.asInstanceOf[Long]
+@SerialVersionUID(13.asInstanceOf[Long]) case class IdentifyMessage1(userName: String, user: User, code: Int)
+ ^
+t6988.scala:8: error: annotation argument needs to be a constant; found: O.SerialUID
+@SerialVersionUID(O.SerialUID) case class IdentifyMessage3(userName: String, user: User, code: Int)
+ ^
+two errors found
diff --git a/test/files/neg/t6988.scala b/test/files/neg/t6988.scala
new file mode 100644
index 0000000000..8171dc9dd0
--- /dev/null
+++ b/test/files/neg/t6988.scala
@@ -0,0 +1,10 @@
+case class User()
+
+@SerialVersionUID(13.asInstanceOf[Long]) case class IdentifyMessage1(userName: String, user: User, code: Int)
+@SerialVersionUID(13l) case class IdentifyMessage2(userName: String, user: User, code: Int)
+object O {
+ val SerialUID = "13".toLong
+}
+@SerialVersionUID(O.SerialUID) case class IdentifyMessage3(userName: String, user: User, code: Int)
+
+
diff --git a/test/files/neg/t8325-b.check b/test/files/neg/t8325-b.check
new file mode 100644
index 0000000000..ec80826dc0
--- /dev/null
+++ b/test/files/neg/t8325-b.check
@@ -0,0 +1,10 @@
+t8325-b.scala:3: error: Unmatched closing brace '}' ignored here
+ def k(is: Int*} = ???
+ ^
+t8325-b.scala:3: error: ';' expected but '=' found.
+ def k(is: Int*} = ???
+ ^
+t8325-b.scala:4: error: eof expected but '}' found.
+}
+^
+three errors found
diff --git a/test/files/neg/t8325-b.scala b/test/files/neg/t8325-b.scala
new file mode 100644
index 0000000000..6ac78708bb
--- /dev/null
+++ b/test/files/neg/t8325-b.scala
@@ -0,0 +1,4 @@
+
+trait Test {
+ def k(is: Int*} = ???
+}
diff --git a/test/files/neg/t8325-c.check b/test/files/neg/t8325-c.check
new file mode 100644
index 0000000000..51ea4988a6
--- /dev/null
+++ b/test/files/neg/t8325-c.check
@@ -0,0 +1,7 @@
+t8325-c.scala:3: error: identifier expected but ')' found.
+ def k(xx: Int`*`) = ???
+ ^
+t8325-c.scala:4: error: ')' expected but '}' found.
+}
+^
+two errors found
diff --git a/test/files/neg/t8325-c.scala b/test/files/neg/t8325-c.scala
new file mode 100644
index 0000000000..076202df3f
--- /dev/null
+++ b/test/files/neg/t8325-c.scala
@@ -0,0 +1,4 @@
+
+trait Test {
+ def k(xx: Int`*`) = ???
+}
diff --git a/test/files/neg/t8325.check b/test/files/neg/t8325.check
new file mode 100644
index 0000000000..175a0db415
--- /dev/null
+++ b/test/files/neg/t8325.check
@@ -0,0 +1,15 @@
+t8325.scala:5: error: *-parameter must come last
+ def f(is: Int*, s: String) = ???
+ ^
+t8325.scala:7: error: *-parameter must come last
+ def h(is: Int * String *, s: String) = ???
+ ^
+t8325.scala:10: error: type mismatch;
+ found : Int(5)
+ required: Int*
+ def j(is: Int* = 5) = ???
+ ^
+t8325.scala:10: error: a parameter section with a `*'-parameter is not allowed to have default arguments
+ def j(is: Int* = 5) = ???
+ ^
+four errors found
diff --git a/test/files/neg/t8325.scala b/test/files/neg/t8325.scala
new file mode 100644
index 0000000000..3813797e83
--- /dev/null
+++ b/test/files/neg/t8325.scala
@@ -0,0 +1,11 @@
+
+trait Test {
+ type OK[A,B] = A Tuple2 B
+ type *[A,B] = A Tuple2 B
+ def f(is: Int*, s: String) = ???
+ def g(is: Int * String, s: String) = ??? // OK
+ def h(is: Int * String *, s: String) = ???
+ // won't recover from following
+ //def i(is: Int OK) = ??? //error: identifier expected but ')' found.
+ def j(is: Int* = 5) = ???
+}
diff --git a/test/files/pos/dotless-targs.flags b/test/files/pos/dotless-targs.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/pos/dotless-targs.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/pos/t8157-2.10.flags b/test/files/pos/t8157-2.10.flags
new file mode 100644
index 0000000000..94c8056747
--- /dev/null
+++ b/test/files/pos/t8157-2.10.flags
@@ -0,0 +1 @@
+-Xsource:2.10
diff --git a/test/files/pos/t8157-2.10.scala b/test/files/pos/t8157-2.10.scala
new file mode 100644
index 0000000000..597585a96d
--- /dev/null
+++ b/test/files/pos/t8157-2.10.scala
@@ -0,0 +1,5 @@
+object Test { // PolyTYped function default arg unicity check,
+ // fails in 2.11, authorized under -Xsource:2.10
+ def foo(printer: Any, question: => String, show: Boolean = false)(op: => Any): Any = ???
+ def foo[T](question: => String, show: Boolean)(op: => Any = ()): Any = ???
+}
diff --git a/test/files/pos/t8325.scala b/test/files/pos/t8325.scala
new file mode 100644
index 0000000000..af33ee7bb3
--- /dev/null
+++ b/test/files/pos/t8325.scala
@@ -0,0 +1,9 @@
+
+trait Test {
+ type +[A, B] = (A, B)
+ type *[A, B] = (A, B)
+
+ type X[A, B] = A + B
+ type Y[A, B] = A * B
+ type Z[A, B] = A `*` B
+}
diff --git a/test/files/pos/t8523.flags b/test/files/pos/t8523.flags
new file mode 100644
index 0000000000..c7d406c649
--- /dev/null
+++ b/test/files/pos/t8523.flags
@@ -0,0 +1 @@
+-Ywarn-dead-code -Xfatal-warnings \ No newline at end of file
diff --git a/test/files/pos/t8523.scala b/test/files/pos/t8523.scala
new file mode 100644
index 0000000000..dfcb35404d
--- /dev/null
+++ b/test/files/pos/t8523.scala
@@ -0,0 +1,10 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+class Impl(val c: Context) {
+ def impl: c.Tree = ???
+}
+
+object Macros {
+ def foo: Any = macro Impl.impl
+} \ No newline at end of file
diff --git a/test/files/pos/t8531/MyEnum.java b/test/files/pos/t8531/MyEnum.java
new file mode 100644
index 0000000000..06cc128a79
--- /dev/null
+++ b/test/files/pos/t8531/MyEnum.java
@@ -0,0 +1,5 @@
+
+package foobar;
+public enum MyEnum {
+A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, A90, A91, A92, A93, A94, A95, A96, A97, A98, A99, A100, A101, A102, A103, A104, A105, A106, A107, A108, A109, A110, A111, A112, A113, A114, A115, A116, A117, A118, A119, A120, A121, A122, A123, A124, A125, A126, A127, A128, A129, A130, A131, A132, A133, A134, A135, A136, A137, A138, A139, A140, A141, A142, A143, A144, A145, A146, A147, A148, A149, A150, A151, A152, A153, A154, A155, A156, A157, A158, A159, A160, A161, A162, A163, A164, A165, A166, A167, A168, A169, A170, A171, A172, A173, A174, A175, A176, A177, A178, A179, A180, A181, A182, A183, A184, A185, A186, A187, A188, A189, A190, A191, A192, A193;
+}
diff --git a/test/files/pos/t8531/Test.scala b/test/files/pos/t8531/Test.scala
new file mode 100644
index 0000000000..59861435a6
--- /dev/null
+++ b/test/files/pos/t8531/Test.scala
@@ -0,0 +1,24 @@
+package test
+
+// takes > 50s and > 800M heap to compile under 2.11.0
+import foobar._
+class `SI-8531` {
+ //https://issues.scala-lang.org/browse/SI-8531
+
+ import MyEnum._
+ def foo(e1: MyEnum, e2: MyEnum) = (e1, e2) match {
+ case (A1, x) => "a1"
+ case (x, A1) => "a1"
+ case (A2, x) => "a2"
+ case (x, A2) => "a2"
+ case (A3, x) => "a3"
+ case (x, A3) => "a3"
+ case (A4, x) => "a4"
+ case (x, A4) => "a4"
+ case (A5, x) => "a5"
+ case (x, A5) => "a5"
+ case (A6, x) => "a6"
+ case (x, A6) => "a6"
+ case (a, b) => "ab"
+ }
+}
diff --git a/test/files/pos/t8546.flags b/test/files/pos/t8546.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/pos/t8546.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/pos/t8546.scala b/test/files/pos/t8546.scala
new file mode 100644
index 0000000000..c39d749b4c
--- /dev/null
+++ b/test/files/pos/t8546.scala
@@ -0,0 +1,49 @@
+package test
+
+class F1() {
+ private sealed abstract class T
+ private case class A(m: Int) extends T
+ private case class B() extends T
+ private case object C extends T
+
+ // No warnings here
+ private def foo(t: T) = t match {
+ case A(m) => println("A:" + m)
+ case B() => println("B")
+ case C => println("C")
+ }
+
+ def test(m: Int): Unit = {
+ foo(A(m))
+ foo(B())
+ foo(C)
+ }
+}
+
+class F2[M]() {
+ private sealed abstract class T
+ private case class A(m: M) extends T
+ private case class B() extends T
+ private case object C extends T
+
+ // match may not be exhaustive. It would fail on the following input: C
+ private def foo(t: T) = t match {
+ case A(m) => println("A:" + m)
+ case B() => println("B")
+ case C => println("C")
+ }
+
+ def test(m: M): Unit = {
+ foo(A(m))
+ foo(B())
+ foo(C)
+ }
+
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ new F1().test(1)
+ new F2[Int]().test(1)
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/t8578.flags b/test/files/pos/t8578.flags
new file mode 100644
index 0000000000..48b438ddf8
--- /dev/null
+++ b/test/files/pos/t8578.flags
@@ -0,0 +1 @@
+-Ydelambdafy:method
diff --git a/test/files/pos/t8578.scala b/test/files/pos/t8578.scala
new file mode 100644
index 0000000000..879b5f5550
--- /dev/null
+++ b/test/files/pos/t8578.scala
@@ -0,0 +1,18 @@
+class DuplicateClassName {
+ () => {
+ {() => ()}
+ {() => ()}
+ {() => ()}
+ {() => ()}
+ {() => ()}
+ {() => ()}
+ {() => ()}
+ {() => ()}
+ {() => ()}
+ {() => () => ()}
+ {() => ()}
+ }
+}
+// Was:
+// Different class symbols have the same bytecode-level internal name:
+// name: DuplicateClassName$lambda$$$anonfun$111 \ No newline at end of file
diff --git a/test/files/pos/t8617.flags b/test/files/pos/t8617.flags
new file mode 100644
index 0000000000..281f0a10cd
--- /dev/null
+++ b/test/files/pos/t8617.flags
@@ -0,0 +1 @@
+-Yrangepos
diff --git a/test/files/pos/t8617.scala b/test/files/pos/t8617.scala
new file mode 100644
index 0000000000..fc825bbcba
--- /dev/null
+++ b/test/files/pos/t8617.scala
@@ -0,0 +1,10 @@
+object Test {
+ def foo[A] = implicitly[OptManifest[A]] // was "unpositioned tree" under -Yrangepos
+
+ // These did not crash, but testing for good measure.
+ implicitly[OptManifest[String]]
+ implicitly[Manifest[String]]
+
+ implicitly[reflect.ClassTag[String]]
+ implicitly[reflect.runtime.universe.TypeTag[String]]
+}
diff --git a/test/files/pos/t8625.scala b/test/files/pos/t8625.scala
new file mode 100644
index 0000000000..95c4b0dbcd
--- /dev/null
+++ b/test/files/pos/t8625.scala
@@ -0,0 +1,5 @@
+object Test {
+ def f1(a: Boolean, b: Boolean) = (a || ???) && (b || ???)
+ def f2(a: Boolean, b: Boolean) = (a || ???) && b
+ def f3(a: Boolean, b: Boolean) = (a && ???) || b
+}
diff --git a/test/files/run/applydynamic_sip.flags b/test/files/run/applydynamic_sip.flags
index 1141f97507..ba6d37305e 100644
--- a/test/files/run/applydynamic_sip.flags
+++ b/test/files/run/applydynamic_sip.flags
@@ -1 +1,2 @@
+-Yrangepos:false
-language:dynamics
diff --git a/test/files/run/classfile-format-51.scala b/test/files/run/classfile-format-51.scala
index f92382d89b..24b1ee8397 100644
--- a/test/files/run/classfile-format-51.scala
+++ b/test/files/run/classfile-format-51.scala
@@ -32,7 +32,7 @@ object Test extends DirectTest {
val constructor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)
constructor.visitCode()
constructor.visitVarInsn(ALOAD, 0)
- constructor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V")
+ constructor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
constructor.visitInsn(RETURN)
constructor.visitMaxs(1, 1)
constructor.visitEnd()
@@ -47,19 +47,19 @@ object Test extends DirectTest {
val bootstrap = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, bootstrapMethodName, bootStrapMethodType, null, null)
bootstrap.visitCode()
// val lookup = MethodHandles.lookup();
- bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;")
+ bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false)
bootstrap.visitVarInsn(ASTORE, 3) // lookup
// val clazz = lookup.lookupClass();
bootstrap.visitVarInsn(ALOAD, 3) // lookup
- bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;")
+ bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false)
bootstrap.visitVarInsn(ASTORE, 4) // clazz
// val methodType = MethodType.fromMethodDescriptorString("()Ljava/lang/String, clazz.getClassLoader()")
bootstrap.visitLdcInsn("()Ljava/lang/String;")
bootstrap.visitVarInsn(ALOAD, 4) // CLAZZ
- bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;")
- bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;")
+ bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false)
+ bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false)
bootstrap.visitVarInsn(ASTORE, 5) // methodType
// val methodHandle = lookup.findStatic(thisClass, "target", methodType)
@@ -67,14 +67,14 @@ object Test extends DirectTest {
bootstrap.visitVarInsn(ALOAD, 4) // clazz
bootstrap.visitLdcInsn("target")
bootstrap.visitVarInsn(ALOAD, 5) // methodType
- bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;")
+ bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false)
bootstrap.visitVarInsn(ASTORE, 6) // methodHandle
// new ConstantCallSite(methodHandle)
bootstrap.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite")
bootstrap.visitInsn(DUP)
bootstrap.visitVarInsn(ALOAD, 6) // methodHandle
- bootstrap.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V")
+ bootstrap.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false)
bootstrap.visitInsn(ARETURN)
bootstrap.visitMaxs(4,7)
bootstrap.visitEnd()
diff --git a/test/files/run/interop_typetags_are_manifests.flags b/test/files/run/interop_typetags_are_manifests.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/run/interop_typetags_are_manifests.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/run/large_class.check b/test/files/run/large_class.check
new file mode 100644
index 0000000000..0585c267ac
--- /dev/null
+++ b/test/files/run/large_class.check
@@ -0,0 +1,3 @@
+newSource1.scala:1: error: Could not write class BigEnoughToFail because it exceeds JVM code size limits. Class file too large!
+class BigEnoughToFail {
+ ^
diff --git a/test/files/run/large_class.scala b/test/files/run/large_class.scala
new file mode 100644
index 0000000000..aa486ef8f7
--- /dev/null
+++ b/test/files/run/large_class.scala
@@ -0,0 +1,27 @@
+import scala.tools.partest._
+import java.io.{Console => _, _}
+
+// a cold run of partest takes about 15s for this test on my laptop
+object Test extends DirectTest {
+ override def extraSettings: String = "-usejavacp -d " + testOutput.path
+
+ def s(n: Int) = "\""+n+"\""
+
+ override def code
+ = s"""
+ |class BigEnoughToFail {
+ | def m(a: String, b: String, c: String, d: String, e: String, f: String) = null
+ | ${(1 to 5500) map (n => "def f"+n+" = m("+ s(n+10000)+","+
+ s(n+20000)+","+
+ s(n+30000)+","+
+ s(n+40000)+","+
+ s(n+50000)+","+
+ s(n+60000)+")") mkString ";"}
+ |}""".stripMargin.trim
+
+ override def show(): Unit = {
+ Console.withErr(System.out) {
+ compile()
+ }
+ }
+}
diff --git a/test/files/run/macro-openmacros.flags b/test/files/run/macro-openmacros.flags
index cd66464f2f..2433c055a4 100644
--- a/test/files/run/macro-openmacros.flags
+++ b/test/files/run/macro-openmacros.flags
@@ -1 +1,2 @@
--language:experimental.macros \ No newline at end of file
+-Yrangepos:false
+-language:experimental.macros
diff --git a/test/files/run/macro-parse-position.flags b/test/files/run/macro-parse-position.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/run/macro-parse-position.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/run/macroPlugins-macroExpand.flags b/test/files/run/macroPlugins-macroExpand.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/run/macroPlugins-macroExpand.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/run/macroPlugins-typedMacroBody.flags b/test/files/run/macroPlugins-typedMacroBody.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/run/macroPlugins-typedMacroBody.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/run/t3569.scala b/test/files/run/t3569.scala
index 91d437e0e3..eb3b424439 100644
--- a/test/files/run/t3569.scala
+++ b/test/files/run/t3569.scala
@@ -26,7 +26,8 @@ object Test {
s.x += 1
println(s.x)
- (classOf[X].getDeclaredFields map ("" + _)).sorted foreach println
+ // under -Xcheckinit there's an additional $init$ field
+ (classOf[X].getDeclaredFields map ("" + _)).sorted.filter(_ != "private volatile byte Test$X.bitmap$init$0") foreach println
(classOf[Y].getDeclaredFields map ("" + _)).sorted foreach println
}
}
diff --git a/test/files/run/t5256h.scala b/test/files/run/t5256h.scala
index f58aa6dbe7..435124a469 100644
--- a/test/files/run/t5256h.scala
+++ b/test/files/run/t5256h.scala
@@ -6,5 +6,6 @@ object Test extends App {
val c = cm.classSymbol(mutant.getClass)
println(c)
println(c.fullName)
- println(c.info)
+ // under -Xcheckinit there's an additional $init$ field
+ c.info.toString.lines.filter(_ != " private var bitmap$init$0: Boolean") foreach println
}
diff --git a/test/files/run/t5905-features.flags b/test/files/run/t5905-features.flags
new file mode 100644
index 0000000000..ad51758c39
--- /dev/null
+++ b/test/files/run/t5905-features.flags
@@ -0,0 +1 @@
+-nowarn
diff --git a/test/files/run/t5905-features.scala b/test/files/run/t5905-features.scala
new file mode 100644
index 0000000000..a3848eef2a
--- /dev/null
+++ b/test/files/run/t5905-features.scala
@@ -0,0 +1,29 @@
+
+import tools.partest.DirectTest
+
+// verify that all languageFeature names are accepted by -language
+object Test extends DirectTest {
+ override def code = "class Code { def f = (1 to 10) size }" // exercise a feature
+
+ override def extraSettings = s"-usejavacp -d ${testOutput.path}"
+
+ override def show() = {
+ val global = newCompiler("-language:postfixOps", "-Ystop-after:typer")
+ compileString(global)(code)
+ import global._
+ exitingTyper {
+ //def isFeature(s: Symbol) = s.annotations.exists((a: AnnotationInfo) => a.tpe <:< typeOf[scala.annotation.meta.languageFeature])
+ def isFeature(s: Symbol) = s hasAnnotation definitions.LanguageFeatureAnnot
+ val langf = definitions.languageFeatureModule.typeSignature
+ val feats = langf.declarations filter (s => isFeature(s)) map (_.name.decoded)
+ val xmen = langf.member(TermName("experimental")).typeSignature.declarations filter (s => isFeature(s)) map (s => s"experimental.${s.name.decoded}")
+ val all = (feats ++ xmen) mkString ","
+
+ assert(feats.nonEmpty, "Test must find feature flags.")
+
+ //dynamics,postfixOps,reflectiveCalls,implicitConversions,higherKinds,existentials,experimental.macros
+ compile(s"-language:$all")
+ }
+ }
+}
+
diff --git a/test/files/run/t5905b-features.check b/test/files/run/t5905b-features.check
new file mode 100644
index 0000000000..08c76d74aa
--- /dev/null
+++ b/test/files/run/t5905b-features.check
@@ -0,0 +1 @@
+'noob' is not a valid choice for '-language'
diff --git a/test/files/run/t5905b-features.scala b/test/files/run/t5905b-features.scala
new file mode 100644
index 0000000000..627df8334b
--- /dev/null
+++ b/test/files/run/t5905b-features.scala
@@ -0,0 +1,15 @@
+
+import tools.partest.DirectTest
+
+// verify that only languageFeature names are accepted by -language
+object Test extends DirectTest {
+ override def code = "class Code"
+
+ override def extraSettings = s"-usejavacp -d ${testOutput.path}"
+
+ override def show() = {
+ //compile("-language", "--") // no error
+ compile(s"-language:noob")
+ }
+}
+
diff --git a/test/files/run/t6327.flags b/test/files/run/t6327.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/run/t6327.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/run/t6663.flags b/test/files/run/t6663.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/run/t6663.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/run/t6731.flags b/test/files/run/t6731.flags
new file mode 100644
index 0000000000..ea7fc37e1a
--- /dev/null
+++ b/test/files/run/t6731.flags
@@ -0,0 +1 @@
+-Yrangepos:false
diff --git a/test/files/run/t6988.check b/test/files/run/t6988.check
new file mode 100644
index 0000000000..5db04832d6
--- /dev/null
+++ b/test/files/run/t6988.check
@@ -0,0 +1,2 @@
+#1 13
+#2 13
diff --git a/test/files/run/t6988.scala b/test/files/run/t6988.scala
new file mode 100644
index 0000000000..45dfe33461
--- /dev/null
+++ b/test/files/run/t6988.scala
@@ -0,0 +1,9 @@
+case class User()
+
+@SerialVersionUID(13l) case class IdentifyMessage1(userName: String, user: User, code: Int)
+@SerialVersionUID(10l + 3l) case class IdentifyMessage2(userName: String, user: User, code: Int)
+
+object Test extends App {
+ println("#1 " + java.io.ObjectStreamClass.lookup(IdentifyMessage1("hei", User(), 8).getClass).getSerialVersionUID)
+ println("#2 " + java.io.ObjectStreamClass.lookup(IdentifyMessage2("hei", User(), 8).getClass).getSerialVersionUID)
+}
diff --git a/test/files/run/t7852.scala b/test/files/run/t7852.scala
index c93db718fd..1679067510 100644
--- a/test/files/run/t7852.scala
+++ b/test/files/run/t7852.scala
@@ -12,7 +12,7 @@ object Test extends BytecodeTest {
val classNode = loadClassNode("Lean")
val methodNode = getMethod(classNode, methodName)
val got = countNullChecks(methodNode.instructions)
- assert(got == expected, s"expected $expected but got $got comparisons")
+ assert(got == expected, s"$methodName: expected $expected but got $got comparisons")
}
test("string", expected = 0)
test("module", expected = 0)
diff --git a/test/files/run/t7974.flags b/test/files/run/t7974.flags
new file mode 100644
index 0000000000..5fc2a03894
--- /dev/null
+++ b/test/files/run/t7974.flags
@@ -0,0 +1 @@
+-Xcheckinit:false
diff --git a/test/files/run/t7974/Test.scala b/test/files/run/t7974/Test.scala
index 9403ea332b..433d9061a7 100644
--- a/test/files/run/t7974/Test.scala
+++ b/test/files/run/t7974/Test.scala
@@ -9,7 +9,7 @@ object Test extends BytecodeTest {
val classNode = loadClassNode("Symbols", skipDebugInfo = false)
val textifier = new Textifier
classNode.accept(new TraceClassVisitor(null, textifier, null))
-
+
val classString = stringFromWriter(w => textifier.print(w))
val result =
classString.split('\n')
diff --git a/test/files/run/t8196.check b/test/files/run/t8196.check
new file mode 100644
index 0000000000..b32f42cf07
--- /dev/null
+++ b/test/files/run/t8196.check
@@ -0,0 +1,7 @@
+t8196.scala:26: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
+ form2.g1 // comment this line in order to make the test pass
+ ^
+warning: there were 2 feature warning(s); re-run with -feature for details
+Scope{
+ final private val f1: Int
+}
diff --git a/test/files/run/t8196.scala b/test/files/run/t8196.scala
new file mode 100644
index 0000000000..e219ac166b
--- /dev/null
+++ b/test/files/run/t8196.scala
@@ -0,0 +1,51 @@
+import scala.reflect.runtime.{ universe => ru }
+
+object Test extends App {
+
+ trait FormTrait {
+
+ val runtimeMirror = ru.runtimeMirror(this.getClass.getClassLoader)
+ val instanceMirror = runtimeMirror.reflect(this)
+ val members = instanceMirror.symbol.typeSignature.members
+ def fields = members.filter(_.typeSignature <:< ru.typeOf[Int])
+ }
+
+ val f = () => {
+
+ class Form1 extends FormTrait {
+ val f1 = 5
+ }
+ val form1 = new Form1
+
+ println(form1.fields)
+
+ val form2 = new FormTrait {
+ val g1 = new Form1
+ }
+
+ form2.g1 // comment this line in order to make the test pass
+ ()
+ }
+
+ val g = () => {
+ // Reported as SI-8195, same root cause
+ trait Form {
+
+ private val runtimeMirror = ru.runtimeMirror(this.getClass.getClassLoader)
+ private val instanceMirror = runtimeMirror.reflect(this)
+ private val members = instanceMirror.symbol.typeSignature.members
+
+ }
+
+ val f1 = new Form {
+ val a = 1
+ }
+
+ val f2 = new Form {
+ val b = f1.a
+ }
+ }
+
+ f()
+ g()
+}
diff --git a/test/files/run/t8442.check b/test/files/run/t8442.check
new file mode 100644
index 0000000000..ce9e8b52ff
--- /dev/null
+++ b/test/files/run/t8442.check
@@ -0,0 +1 @@
+pos: NoPosition Class A_1 not found - continuing with a stub. WARNING
diff --git a/test/files/run/t8442/A_1.java b/test/files/run/t8442/A_1.java
new file mode 100644
index 0000000000..227451eecd
--- /dev/null
+++ b/test/files/run/t8442/A_1.java
@@ -0,0 +1,4 @@
+@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface A_1 {
+
+} \ No newline at end of file
diff --git a/test/files/run/t8442/B_1.java b/test/files/run/t8442/B_1.java
new file mode 100644
index 0000000000..1680684495
--- /dev/null
+++ b/test/files/run/t8442/B_1.java
@@ -0,0 +1,3 @@
+public class B_1 {
+ @A_1 public String get() { return ""; }
+}
diff --git a/test/files/run/t8442/C_2.scala b/test/files/run/t8442/C_2.scala
new file mode 100644
index 0000000000..d75d4bd910
--- /dev/null
+++ b/test/files/run/t8442/C_2.scala
@@ -0,0 +1,5 @@
+class C_2 {
+ def foo(b: B_1) {
+ b.get()
+ }
+}
diff --git a/test/files/run/t8442/Test.scala b/test/files/run/t8442/Test.scala
new file mode 100644
index 0000000000..ff6da4e206
--- /dev/null
+++ b/test/files/run/t8442/Test.scala
@@ -0,0 +1,29 @@
+import scala.tools.partest._
+import java.io.File
+
+object Test extends StoreReporterDirectTest {
+ def code = ???
+
+ def compileCode(code: String) = {
+ val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator")
+ compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code)
+ }
+
+ def app = """
+ class C_2 {
+ def foo(b: B_1) {
+ b.get()
+ }
+ }
+ """
+
+ def show(): Unit = {
+ val tClass = new File(testOutput.path, "A_1.class")
+ assert(tClass.exists)
+ assert(tClass.delete())
+
+ // Expecting stub symbol warning, but no stack trace!
+ compileCode(app)
+ println(filteredInfos.mkString("\n"))
+ }
+}
diff --git a/test/files/run/t8549.check b/test/files/run/t8549.check
new file mode 100644
index 0000000000..a92ddc0e51
--- /dev/null
+++ b/test/files/run/t8549.check
@@ -0,0 +1 @@
+warning: there were 2 deprecation warning(s); re-run with -deprecation for details
diff --git a/test/files/run/t8549.scala b/test/files/run/t8549.scala
new file mode 100644
index 0000000000..d3355208fa
--- /dev/null
+++ b/test/files/run/t8549.scala
@@ -0,0 +1,186 @@
+import javax.xml.bind.DatatypeConverter._
+import scala.reflect.io.File
+
+// This test is self-modifying when run as follows:
+//
+// (export V=v2.10.4
+// scalac-hash $V test/files/run/t8549.scala
+// scala-hash $V -Doverwrite.source=test/files/run/t8549.scala Test
+// )
+//
+// Use this to re-establish a baseline for serialization compatibility.
+object Test extends App {
+ val overwrite: Option[File] = sys.props.get("overwrite.source").map(s => new File(new java.io.File(s)))
+
+ def serialize(o: AnyRef): String = {
+ val bos = new java.io.ByteArrayOutputStream()
+ val out = new java.io.ObjectOutputStream(bos)
+ out.writeObject(o)
+ out.flush()
+ printBase64Binary(bos.toByteArray())
+ }
+
+ def amend(file: File)(f: String => String) {
+ file.writeAll(f(file.slurp))
+ }
+ def quote(s: String) = List("\"", s, "\"").mkString
+
+ def patch(file: File, line: Int, prevResult: String, result: String) {
+ amend(file) {
+ content =>
+ content.lines.toList.zipWithIndex.map {
+ case (content, i) if i == line - 1 =>
+ val newContent = content.replaceAllLiterally(quote(prevResult), quote(result))
+ if (newContent != content)
+ println(s"- $content\n+ $newContent\n")
+ newContent
+ case (content, _) => content
+ }.mkString("\n")
+ }
+ }
+
+ def updateComment(file: File) {
+ val timestamp = {
+ import java.text.SimpleDateFormat
+ val sdf = new SimpleDateFormat("yyyyMMdd-HH:mm:ss")
+ sdf.format(new java.util.Date)
+ }
+ val newComment = s" // Generated on $timestamp with Scala ${scala.util.Properties.versionString})"
+ amend(file) {
+ content =>
+ content.lines.toList.map {
+ f => f.replaceAll("""^ +// Generated on.*""", newComment)
+ }.mkString("\n")
+ }
+ }
+
+ def deserialize(string: String): AnyRef = {
+ val bis = new java.io.ByteArrayInputStream(parseBase64Binary(string))
+ val in = new java.io.ObjectInputStream(bis)
+ in.readObject()
+ }
+
+ def checkRoundTrip[T <: AnyRef](instance: T)(f: T => AnyRef) {
+ val result = serialize(instance)
+ val reconstituted = deserialize(result).asInstanceOf[T]
+ assert(f(instance) == f(reconstituted), (f(instance), f(reconstituted)))
+ }
+
+ def check[T <: AnyRef](instance: => T)(prevResult: String, f: T => AnyRef = (x: T) => x) {
+ val result = serialize(instance)
+ overwrite match {
+ case Some(f) =>
+ val lineNumberOfLiteralString = Thread.currentThread.getStackTrace.apply(2).getLineNumber
+ patch(f, lineNumberOfLiteralString, prevResult, result)
+ case None =>
+ checkRoundTrip(instance)(f)
+ assert(f(deserialize(prevResult).asInstanceOf[T]) == f(instance), s"$instance != f(deserialize(prevResult))")
+ assert(prevResult == result, s"instance = $instance : ${instance.getClass}\n serialization unstable: ${prevResult}\n found: ${result}")
+ }
+ }
+
+ // Generated on 20140505-14:47:14 with Scala version 2.11.1-20140505-142300-e8562571d2)
+ overwrite.foreach(updateComment)
+
+ check(List(1, 2, 3))( "rO0ABXNyADJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAABAwAAeHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJzcQB+AAIAAAADc3IALHNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3RTZXJpYWxpemVFbmQkilxjW/dTC20CAAB4cHg=")
+ check(Nil)( "rO0ABXNyADJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAABAwAAeHBzcgAsc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdFNlcmlhbGl6ZUVuZCSKXGNb91MLbQIAAHhweA==")
+
+ // TODO SI-8576 unstable under -Xcheckinit
+ // check(Vector(1))( "rO0ABXNyACFzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5WZWN0b3Lkd3dcHq6PXAIAC0kABWRlcHRoWgAFZGlydHlJAAhlbmRJbmRleEkABWZvY3VzSQAKc3RhcnRJbmRleFsACGRpc3BsYXkwdAATW0xqYXZhL2xhbmcvT2JqZWN0O1sACGRpc3BsYXkxcQB+AAFbAAhkaXNwbGF5MnEAfgABWwAIZGlzcGxheTNxAH4AAVsACGRpc3BsYXk0cQB+AAFbAAhkaXNwbGF5NXEAfgABeHAAAAABAAAAAAEAAAAAAAAAAHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAACBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcA==")
+ // check(Vector())( "rO0ABXNyACFzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5WZWN0b3Lkd3dcHq6PXAIAC0kABWRlcHRoWgAFZGlydHlJAAhlbmRJbmRleEkABWZvY3VzSQAKc3RhcnRJbmRleFsACGRpc3BsYXkwdAATW0xqYXZhL2xhbmcvT2JqZWN0O1sACGRpc3BsYXkxcQB+AAFbAAhkaXNwbGF5MnEAfgABWwAIZGlzcGxheTNxAH4AAVsACGRpc3BsYXk0cQB+AAFbAAhkaXNwbGF5NXEAfgABeHAAAAAAAAAAAAAAAAAAAAAAAHBwcHBwcA==")
+
+ import collection.{ mutable, immutable }
+
+ class C
+ check(reflect.classTag[C])("rO0ABXNyAB5zY2FsYS5yZWZsZWN0LkNsYXNzVGFnJCRhbm9uJDG7ePPrmQBkhgIAAUwAD3J1bnRpbWVDbGFzczEkMXQAEUxqYXZhL2xhbmcvQ2xhc3M7eHB2cgAGVGVzdCRDAAAAAAAAAAAAAAB4cA==")
+ check(reflect.classTag[Int])("rO0ABXNyACVzY2FsYS5yZWZsZWN0Lk1hbmlmZXN0RmFjdG9yeSQkYW5vbiQ5zfmiSVNjtVICAAB4cgAcc2NhbGEucmVmbGVjdC5BbnlWYWxNYW5pZmVzdAAAAAAAAAABAgABTAAIdG9TdHJpbmd0ABJMamF2YS9sYW5nL1N0cmluZzt4cHQAA0ludA==")
+ check(reflect.classTag[String])("rO0ABXNyAB5zY2FsYS5yZWZsZWN0LkNsYXNzVGFnJCRhbm9uJDG7ePPrmQBkhgIAAUwAD3J1bnRpbWVDbGFzczEkMXQAEUxqYXZhL2xhbmcvQ2xhc3M7eHB2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHA=")
+ check(reflect.classTag[Object])("rO0ABXNyACVzY2FsYS5yZWZsZWN0Lk1hbmlmZXN0RmFjdG9yeSQkYW5vbiQymPrtq/Ci1gsCAAB4cgAtc2NhbGEucmVmbGVjdC5NYW5pZmVzdEZhY3RvcnkkUGhhbnRvbU1hbmlmZXN0rzigP7KRh/kCAAFMAAh0b1N0cmluZ3QAEkxqYXZhL2xhbmcvU3RyaW5nO3hyAC9zY2FsYS5yZWZsZWN0Lk1hbmlmZXN0RmFjdG9yeSRDbGFzc1R5cGVNYW5pZmVzdFq6NWvfTgYFAgADTAAGcHJlZml4dAAOTHNjYWxhL09wdGlvbjtMAAxydW50aW1lQ2xhc3N0ABFMamF2YS9sYW5nL0NsYXNzO0wADXR5cGVBcmd1bWVudHN0ACFMc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvTGlzdDt4cHNyAAtzY2FsYS5Ob25lJEZQJPZTypSsAgAAeHIADHNjYWxhLk9wdGlvbv5pN/3bDmZ0AgAAeHB2cgAQamF2YS5sYW5nLk9iamVjdAAAAAAAAAAAAAAAeHBzcgAyc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdCRTZXJpYWxpemF0aW9uUHJveHkAAAAAAAAAAQMAAHhwc3IALHNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3RTZXJpYWxpemVFbmQkilxjW/dTC20CAAB4cHh0AAZPYmplY3Q=")
+
+ // TODO SI-8576 unstable under -Xcheckinit
+ // check(Enum)( "rO0ABXNyAApUZXN0JEVudW0ketCIyQ8C23MCAAJMAAJWMXQAGUxzY2FsYS9FbnVtZXJhdGlvbiRWYWx1ZTtMAAJWMnQAF0xzY2FsYS9FbnVtZXJhdGlvbiRWYWw7eHIAEXNjYWxhLkVudW1lcmF0aW9udaDN3ZgOWY4CAAhJAAZuZXh0SWRJABtzY2FsYSRFbnVtZXJhdGlvbiQkYm90dG9tSWRJABhzY2FsYSRFbnVtZXJhdGlvbiQkdG9wSWRMABRWYWx1ZU9yZGVyaW5nJG1vZHVsZXQAIkxzY2FsYS9FbnVtZXJhdGlvbiRWYWx1ZU9yZGVyaW5nJDtMAA9WYWx1ZVNldCRtb2R1bGV0AB1Mc2NhbGEvRW51bWVyYXRpb24kVmFsdWVTZXQkO0wACG5leHROYW1ldAAbTHNjYWxhL2NvbGxlY3Rpb24vSXRlcmF0b3I7TAAXc2NhbGEkRW51bWVyYXRpb24kJG5tYXB0AB5Mc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL01hcDtMABdzY2FsYSRFbnVtZXJhdGlvbiQkdm1hcHEAfgAHeHAAAAArAAAAAAAAACtwcHBzcgAgc2NhbGEuY29sbGVjdGlvbi5tdXRhYmxlLkhhc2hNYXAAAAAAAAAAAQMAAHhwdw0AAALuAAAAAAAAAAQAeHNxAH4ACXcNAAAC7gAAAAEAAAAEAHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAAqc3IAFXNjYWxhLkVudW1lcmF0aW9uJFZhbM9pZ6/J/O1PAgACSQAYc2NhbGEkRW51bWVyYXRpb24kVmFsJCRpTAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO3hyABdzY2FsYS5FbnVtZXJhdGlvbiRWYWx1ZWJpfC/tIR1RAgACTAAGJG91dGVydAATTHNjYWxhL0VudW1lcmF0aW9uO0wAHHNjYWxhJEVudW1lcmF0aW9uJCRvdXRlckVudW1xAH4AEnhwcQB+AAhxAH4ACAAAACpweHNyABFUZXN0JEVudW0kJGFub24kMVlIjlmE1sXaAgAAeHEAfgARcQB+AAhxAH4ACHEAfgAT")
+ // check(Enum.V1)( "rO0ABXNyABFUZXN0JEVudW0kJGFub24kMVlIjlmE1sXaAgAAeHIAF3NjYWxhLkVudW1lcmF0aW9uJFZhbHVlYml8L+0hHVECAAJMAAYkb3V0ZXJ0ABNMc2NhbGEvRW51bWVyYXRpb247TAAcc2NhbGEkRW51bWVyYXRpb24kJG91dGVyRW51bXEAfgACeHBzcgAKVGVzdCRFbnVtJHrQiMkPAttzAgACTAACVjF0ABlMc2NhbGEvRW51bWVyYXRpb24kVmFsdWU7TAACVjJ0ABdMc2NhbGEvRW51bWVyYXRpb24kVmFsO3hyABFzY2FsYS5FbnVtZXJhdGlvbnWgzd2YDlmOAgAISQAGbmV4dElkSQAbc2NhbGEkRW51bWVyYXRpb24kJGJvdHRvbUlkSQAYc2NhbGEkRW51bWVyYXRpb24kJHRvcElkTAAUVmFsdWVPcmRlcmluZyRtb2R1bGV0ACJMc2NhbGEvRW51bWVyYXRpb24kVmFsdWVPcmRlcmluZyQ7TAAPVmFsdWVTZXQkbW9kdWxldAAdTHNjYWxhL0VudW1lcmF0aW9uJFZhbHVlU2V0JDtMAAhuZXh0TmFtZXQAG0xzY2FsYS9jb2xsZWN0aW9uL0l0ZXJhdG9yO0wAF3NjYWxhJEVudW1lcmF0aW9uJCRubWFwdAAeTHNjYWxhL2NvbGxlY3Rpb24vbXV0YWJsZS9NYXA7TAAXc2NhbGEkRW51bWVyYXRpb24kJHZtYXBxAH4AC3hwAAAAKwAAAAAAAAArcHBwc3IAIHNjYWxhLmNvbGxlY3Rpb24ubXV0YWJsZS5IYXNoTWFwAAAAAAAAAAEDAAB4cHcNAAAC7gAAAAAAAAAEAHhzcQB+AA13DQAAAu4AAAABAAAABABzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAKnNyABVzY2FsYS5FbnVtZXJhdGlvbiRWYWzPaWevyfztTwIAAkkAGHNjYWxhJEVudW1lcmF0aW9uJFZhbCQkaUwABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cQB+AAFxAH4ADHEAfgAMAAAAKnB4cQB+AANxAH4AFXEAfgAM")
+ // check(Enum.V2)( "rO0ABXNyABVzY2FsYS5FbnVtZXJhdGlvbiRWYWzPaWevyfztTwIAAkkAGHNjYWxhJEVudW1lcmF0aW9uJFZhbCQkaUwABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cgAXc2NhbGEuRW51bWVyYXRpb24kVmFsdWViaXwv7SEdUQIAAkwABiRvdXRlcnQAE0xzY2FsYS9FbnVtZXJhdGlvbjtMABxzY2FsYSRFbnVtZXJhdGlvbiQkb3V0ZXJFbnVtcQB+AAN4cHNyAApUZXN0JEVudW0ketCIyQ8C23MCAAJMAAJWMXQAGUxzY2FsYS9FbnVtZXJhdGlvbiRWYWx1ZTtMAAJWMnQAF0xzY2FsYS9FbnVtZXJhdGlvbiRWYWw7eHIAEXNjYWxhLkVudW1lcmF0aW9udaDN3ZgOWY4CAAhJAAZuZXh0SWRJABtzY2FsYSRFbnVtZXJhdGlvbiQkYm90dG9tSWRJABhzY2FsYSRFbnVtZXJhdGlvbiQkdG9wSWRMABRWYWx1ZU9yZGVyaW5nJG1vZHVsZXQAIkxzY2FsYS9FbnVtZXJhdGlvbiRWYWx1ZU9yZGVyaW5nJDtMAA9WYWx1ZVNldCRtb2R1bGV0AB1Mc2NhbGEvRW51bWVyYXRpb24kVmFsdWVTZXQkO0wACG5leHROYW1ldAAbTHNjYWxhL2NvbGxlY3Rpb24vSXRlcmF0b3I7TAAXc2NhbGEkRW51bWVyYXRpb24kJG5tYXB0AB5Mc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL01hcDtMABdzY2FsYSRFbnVtZXJhdGlvbiQkdm1hcHEAfgAMeHAAAAArAAAAAAAAACtwcHBzcgAgc2NhbGEuY29sbGVjdGlvbi5tdXRhYmxlLkhhc2hNYXAAAAAAAAAAAQMAAHhwdw0AAALuAAAAAAAAAAQAeHNxAH4ADncNAAAC7gAAAAEAAAAEAHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAAqcQB+AAR4c3IAEVRlc3QkRW51bSQkYW5vbiQxWUiOWYTWxdoCAAB4cQB+AAJxAH4ADXEAfgANcQB+AARxAH4ADQAAACpw")
+
+ // IndexedSeqLike#Elements
+ // TODO SI-8576 throws scala.UnitializedFieldError under -Xcheckinit
+ // check(new immutable.Range(0, 1, 1).iterator)("rO0ABXNyAChzY2FsYS5jb2xsZWN0aW9uLkluZGV4ZWRTZXFMaWtlJEVsZW1lbnRzGF+1cBwmcx0CAANJAANlbmRJAAVpbmRleEwABiRvdXRlcnQAIUxzY2FsYS9jb2xsZWN0aW9uL0luZGV4ZWRTZXFMaWtlO3hwAAAAAQAAAABzcgAgc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuUmFuZ2Vpu6NUqxUyDQIAB0kAA2VuZFoAB2lzRW1wdHlJAAtsYXN0RWxlbWVudEkAEG51bVJhbmdlRWxlbWVudHNJAAVzdGFydEkABHN0ZXBJAA90ZXJtaW5hbEVsZW1lbnR4cAAAAAEAAAAAAAAAAAEAAAAAAAAAAQAAAAE="
+ // , _.toList)
+
+ // check(new collection.concurrent.TrieMap[Any, Any]())( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLmNvbmN1cnJlbnQuVHJpZU1hcKckxpgOIYHPAwAETAALZXF1YWxpdHlvYmp0ABJMc2NhbGEvbWF0aC9FcXVpdjtMAApoYXNoaW5nb2JqdAAcTHNjYWxhL3V0aWwvaGFzaGluZy9IYXNoaW5nO0wABHJvb3R0ABJMamF2YS9sYW5nL09iamVjdDtMAAtyb290dXBkYXRlcnQAOUxqYXZhL3V0aWwvY29uY3VycmVudC9hdG9taWMvQXRvbWljUmVmZXJlbmNlRmllbGRVcGRhdGVyO3hwc3IAMnNjYWxhLmNvbGxlY3Rpb24uY29uY3VycmVudC5UcmllTWFwJE1hbmdsZWRIYXNoaW5nhTBoJQ/mgb0CAAB4cHNyABhzY2FsYS5tYXRoLkVxdWl2JCRhbm9uJDLBbyx4dy/qGwIAAHhwc3IANHNjYWxhLmNvbGxlY3Rpb24uY29uY3VycmVudC5UcmllTWFwU2VyaWFsaXphdGlvbkVuZCSbjdgbbGCt2gIAAHhweA==")
+ // not sure why this one needs stable serialization.
+
+ // TODO SI-8576 unstable under -Xcheckinit
+ check(collection.convert.Wrappers)( "rO0ABXNyACJzY2FsYS5jb2xsZWN0aW9uLmNvbnZlcnQuV3JhcHBlcnMkrrSziizavIECABJMABhEaWN0aW9uYXJ5V3JhcHBlciRtb2R1bGV0ADZMc2NhbGEvY29sbGVjdGlvbi9jb252ZXJ0L1dyYXBwZXJzJERpY3Rpb25hcnlXcmFwcGVyJDtMABZJdGVyYWJsZVdyYXBwZXIkbW9kdWxldAA0THNjYWxhL2NvbGxlY3Rpb24vY29udmVydC9XcmFwcGVycyRJdGVyYWJsZVdyYXBwZXIkO0wAFkl0ZXJhdG9yV3JhcHBlciRtb2R1bGV0ADRMc2NhbGEvY29sbGVjdGlvbi9jb252ZXJ0L1dyYXBwZXJzJEl0ZXJhdG9yV3JhcHBlciQ7TAAZSkNvbGxlY3Rpb25XcmFwcGVyJG1vZHVsZXQAN0xzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkSkNvbGxlY3Rpb25XcmFwcGVyJDtMABxKQ29uY3VycmVudE1hcFdyYXBwZXIkbW9kdWxldAA6THNjYWxhL2NvbGxlY3Rpb24vY29udmVydC9XcmFwcGVycyRKQ29uY3VycmVudE1hcFdyYXBwZXIkO0wAGUpEaWN0aW9uYXJ5V3JhcHBlciRtb2R1bGV0ADdMc2NhbGEvY29sbGVjdGlvbi9jb252ZXJ0L1dyYXBwZXJzJEpEaWN0aW9uYXJ5V3JhcHBlciQ7TAAaSkVudW1lcmF0aW9uV3JhcHBlciRtb2R1bGV0ADhMc2NhbGEvY29sbGVjdGlvbi9jb252ZXJ0L1dyYXBwZXJzJEpFbnVtZXJhdGlvbldyYXBwZXIkO0wAF0pJdGVyYWJsZVdyYXBwZXIkbW9kdWxldAA1THNjYWxhL2NvbGxlY3Rpb24vY29udmVydC9XcmFwcGVycyRKSXRlcmFibGVXcmFwcGVyJDtMABdKSXRlcmF0b3JXcmFwcGVyJG1vZHVsZXQANUxzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkSkl0ZXJhdG9yV3JhcHBlciQ7TAATSkxpc3RXcmFwcGVyJG1vZHVsZXQAMUxzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkSkxpc3RXcmFwcGVyJDtMABJKTWFwV3JhcHBlciRtb2R1bGV0ADBMc2NhbGEvY29sbGVjdGlvbi9jb252ZXJ0L1dyYXBwZXJzJEpNYXBXcmFwcGVyJDtMABlKUHJvcGVydGllc1dyYXBwZXIkbW9kdWxldAA3THNjYWxhL2NvbGxlY3Rpb24vY29udmVydC9XcmFwcGVycyRKUHJvcGVydGllc1dyYXBwZXIkO0wAEkpTZXRXcmFwcGVyJG1vZHVsZXQAMExzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkSlNldFdyYXBwZXIkO0wAG011dGFibGVCdWZmZXJXcmFwcGVyJG1vZHVsZXQAOUxzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkTXV0YWJsZUJ1ZmZlcldyYXBwZXIkO0wAGE11dGFibGVNYXBXcmFwcGVyJG1vZHVsZXQANkxzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkTXV0YWJsZU1hcFdyYXBwZXIkO0wAGE11dGFibGVTZXFXcmFwcGVyJG1vZHVsZXQANkxzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkTXV0YWJsZVNlcVdyYXBwZXIkO0wAGE11dGFibGVTZXRXcmFwcGVyJG1vZHVsZXQANkxzY2FsYS9jb2xsZWN0aW9uL2NvbnZlcnQvV3JhcHBlcnMkTXV0YWJsZVNldFdyYXBwZXIkO0wAEVNlcVdyYXBwZXIkbW9kdWxldAAvTHNjYWxhL2NvbGxlY3Rpb24vY29udmVydC9XcmFwcGVycyRTZXFXcmFwcGVyJDt4cHBwcHBwcHBwcHBwcHBwcHBwcA==")
+
+ check(immutable.BitSet(1, 2, 3))( "rO0ABXNyAClzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5CaXRTZXQkQml0U2V0MR9dg8JGRI8UAgABSgAFZWxlbXN4cgAhc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuQml0U2V0Flz5Ms3qxsoCAAB4cAAAAAAAAAAO")
+ check(immutable.HashMap())( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoTWFwJFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAAB4")
+ check(immutable.HashMap(1 -> 2))( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoTWFwJFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAAFzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJ4")
+ check(immutable.HashMap(1 -> 2, 3 -> 4))( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoTWFwJFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAAJzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJzcQB+AAIAAAADc3EAfgACAAAABHg=")
+ // TODO provoke HashMapCollision1
+
+ check(immutable.HashSet())( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoU2V0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAAB4")
+ check(immutable.HashSet(1))( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoU2V0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAAFzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXg=")
+ check(immutable.HashSet(1, 2))( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoU2V0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAAJzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJ4")
+ check(immutable.HashSet(1, 2, 3))( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoU2V0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJzcQB+AAIAAAADeA==")
+ // TODO provoke HashSetCollision1
+
+ check(immutable.ListMap())( "rO0ABXNyADBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0TWFwJEVtcHR5TGlzdE1hcCSNalsvpBZeDgIAAHhyACJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0TWFwBC1gfIkUSKsCAAB4cA==")
+ check(immutable.ListMap(1 -> 2))( "rO0ABXNyACdzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0TWFwJE5vZGWmciM1Yav+8gIAA0wABiRvdXRlcnQAJExzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS9MaXN0TWFwO0wAA2tleXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABXZhbHVlcQB+AAJ4cgAic2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdE1hcAQtYHyJFEirAgAAeHBzcgAwc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdE1hcCRFbXB0eUxpc3RNYXAkjWpbL6QWXg4CAAB4cQB+AANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABwAAAAI=")
+ check(immutable.Queue())( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5RdWV1ZZY146W3qSuhAgACTAACaW50ACFMc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvTGlzdDtMAANvdXRxAH4AAXhwc3IAMnNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3QkU2VyaWFsaXphdGlvblByb3h5AAAAAAAAAAEDAAB4cHNyACxzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0U2VyaWFsaXplRW5kJIpcY1v3UwttAgAAeHB4cQB+AAQ=")
+ check(immutable.Queue(1, 2, 3))( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5RdWV1ZZY146W3qSuhAgACTAACaW50ACFMc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvTGlzdDtMAANvdXRxAH4AAXhwc3IAMnNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3QkU2VyaWFsaXphdGlvblByb3h5AAAAAAAAAAEDAAB4cHNyACxzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0U2VyaWFsaXplRW5kJIpcY1v3UwttAgAAeHB4c3EAfgADc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcQB+AAgAAAACc3EAfgAIAAAAA3EAfgAGeA==")
+
+ // TODO SI-8576 throws scala.UnitializedFieldError under -Xcheckinit
+ // check(new immutable.Range(0, 1, 1))( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5SYW5nZWm7o1SrFTINAgAHSQADZW5kWgAHaXNFbXB0eUkAC2xhc3RFbGVtZW50SQAQbnVtUmFuZ2VFbGVtZW50c0kABXN0YXJ0SQAEc3RlcEkAD3Rlcm1pbmFsRWxlbWVudHhwAAAAAQAAAAAAAAAAAQAAAAAAAAABAAAAAQ==")
+
+ check(immutable.Set())( "rO0ABXNyAChzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TZXQkRW1wdHlTZXQk8Hk3TFN0uDYCAAB4cA==")
+ check(immutable.Set(1))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TZXQkU2V0MREd3c4yqtWTAgABTAAFZWxlbTF0ABJMamF2YS9sYW5nL09iamVjdDt4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAAB")
+ check(immutable.Set(1, 2))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TZXQkU2V0MqaV02sZQzV0AgACTAAFZWxlbTF0ABJMamF2YS9sYW5nL09iamVjdDtMAAVlbGVtMnEAfgABeHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAwAAAAI=")
+ check(immutable.Set(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TZXQkU2V0M84syT0560SgAgADTAAFZWxlbTF0ABJMamF2YS9sYW5nL09iamVjdDtMAAVlbGVtMnEAfgABTAAFZWxlbTNxAH4AAXhwc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcQB+AAMAAAACc3EAfgADAAAAAw==")
+ check(immutable.Set(1, 2, 3, 4))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TZXQkU2V0NM26psRRbei1AgAETAAFZWxlbTF0ABJMamF2YS9sYW5nL09iamVjdDtMAAVlbGVtMnEAfgABTAAFZWxlbTNxAH4AAUwABWVsZW00cQB+AAF4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgADAAAAAnNxAH4AAwAAAANzcQB+AAMAAAAE")
+ check(immutable.Set(1, 2, 3, 4, 5))( "rO0ABXNyADVzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5IYXNoU2V0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAACAwAAeHB3BAAAAAVzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAABXNxAH4AAgAAAAFzcQB+AAIAAAACc3EAfgACAAAAA3NxAH4AAgAAAAR4")
+
+ check(immutable.Stack(1, 2, 3))( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TdGFjaxtt3qEbMvq+AgABTAAFZWxlbXN0ACFMc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvTGlzdDt4cHNyADJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAABAwAAeHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABQAAAAJzcQB+AAUAAAADc3IALHNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3RTZXJpYWxpemVFbmQkilxjW/dTC20CAAB4cHg=")
+
+ // TODO SI-8576 Uninitialized field: IndexedSeqLike.scala: 56
+ // check(immutable.Stream(1, 2, 3))( "rO0ABXNyACZzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TdHJlYW0kQ29uc/ekjBXM3TlFAgADTAACaGR0ABJMamF2YS9sYW5nL09iamVjdDtMAAV0bEdlbnQAEUxzY2FsYS9GdW5jdGlvbjA7TAAFdGxWYWx0ACNMc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvU3RyZWFtO3hyACFzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5TdHJlYW0552RDntM42gIAAHhwc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcgAtc2NhbGEuY29sbGVjdGlvbi5JdGVyYXRvciQkYW5vbmZ1biR0b1N0cmVhbSQxRWR4We0SX0UCAAFMAAYkb3V0ZXJ0ABtMc2NhbGEvY29sbGVjdGlvbi9JdGVyYXRvcjt4cHNyAChzY2FsYS5jb2xsZWN0aW9uLkluZGV4ZWRTZXFMaWtlJEVsZW1lbnRzGF+1cBwmcx0CAANJAANlbmRJAAVpbmRleEwABiRvdXRlcnQAIUxzY2FsYS9jb2xsZWN0aW9uL0luZGV4ZWRTZXFMaWtlO3hwAAAAAwAAAAFzcgArc2NhbGEuY29sbGVjdGlvbi5tdXRhYmxlLldyYXBwZWRBcnJheSRvZkludMmRLBcI15VjAgABWwAFYXJyYXl0AAJbSXhwdXIAAltJTbpgJnbqsqUCAAB4cAAAAAMAAAABAAAAAgAAAANw")
+
+ check(immutable.TreeSet[Int]())( "rO0ABXNyACJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5UcmVlU2V0sRdVIDjbWAsCAAJMAAhvcmRlcmluZ3QAFUxzY2FsYS9tYXRoL09yZGVyaW5nO0wABHRyZWV0AC5Mc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvUmVkQmxhY2tUcmVlJFRyZWU7eHBzcgAYc2NhbGEubWF0aC5PcmRlcmluZyRJbnQkC4BMdr1Z51wCAAB4cHA=")
+
+ // TODO SI-8576 unstable under -Xcheckinit
+ // check(immutable.TreeSet(1, 2, 3))( "rO0ABXNyACJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5UcmVlU2V0sRdVIDjbWAsCAAJMAAhvcmRlcmluZ3QAFUxzY2FsYS9tYXRoL09yZGVyaW5nO0wABHRyZWV0AC5Mc2NhbGEvY29sbGVjdGlvbi9pbW11dGFibGUvUmVkQmxhY2tUcmVlJFRyZWU7eHBzcgAYc2NhbGEubWF0aC5PcmRlcmluZyRJbnQkC4BMdr1Z51wCAAB4cHNyADFzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5SZWRCbGFja1RyZWUkQmxhY2tUcmVlzRxnCKenVAECAAB4cgAsc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuUmVkQmxhY2tUcmVlJFRyZWVrqCSyHJbsMgIABUkABWNvdW50TAADa2V5dAASTGphdmEvbGFuZy9PYmplY3Q7TAAEbGVmdHEAfgACTAAFcmlnaHRxAH4AAkwABXZhbHVlcQB+AAh4cAAAAANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAnNxAH4ABgAAAAFzcQB+AAoAAAABcHBzcgAXc2NhbGEucnVudGltZS5Cb3hlZFVuaXR0pn1HHezLmgIAAHhwc3EAfgAGAAAAAXNxAH4ACgAAAANwcHEAfgAQcQB+ABA=")
+
+ // TODO SI-8576 Uninitialized field under -Xcheckinit
+ // check(mutable.ArrayBuffer(1, 2, 3))( "rO0ABXNyACRzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQXJyYXlCdWZmZXIVOLBTg4KOcwIAA0kAC2luaXRpYWxTaXplSQAFc2l6ZTBbAAVhcnJheXQAE1tMamF2YS9sYW5nL09iamVjdDt4cAAAABAAAAADdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAEHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAFAAAAAnNxAH4ABQAAAANwcHBwcHBwcHBwcHBw")
+ // TODO SI-8576 Uninitialized field under -Xcheckinit
+ // check(mutable.ArraySeq(1, 2, 3))( "rO0ABXNyACFzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQXJyYXlTZXEVPD3SKEkOcwIAAkkABmxlbmd0aFsABWFycmF5dAATW0xqYXZhL2xhbmcvT2JqZWN0O3hwAAAAA3VyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABQAAAAJzcQB+AAUAAAAD")
+ check(mutable.ArrayStack(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQXJyYXlTdGFja3bdxXbcnLBeAgACSQAqc2NhbGEkY29sbGVjdGlvbiRtdXRhYmxlJEFycmF5U3RhY2skJGluZGV4WwAqc2NhbGEkY29sbGVjdGlvbiRtdXRhYmxlJEFycmF5U3RhY2skJHRhYmxldAATW0xqYXZhL2xhbmcvT2JqZWN0O3hwAAAAA3VyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAANzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAA3NxAH4ABQAAAAJzcQB+AAUAAAAB")
+ check(mutable.DoubleLinkedList(1, 2, 3))( "rO0ABXNyAClzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuRG91YmxlTGlua2VkTGlzdI73LKsKRr1RAgADTAAEZWxlbXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABG5leHR0AB5Mc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL1NlcTtMAARwcmV2cQB+AAJ4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAAc3EAfgAEAAAAAnNxAH4AAHNxAH4ABAAAAANzcQB+AABwcQB+AAtxAH4ACXEAfgAHcQB+AANw")
+
+ check(mutable.HashMap())( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuSGFzaE1hcAAAAAAAAAABAwAAeHB3DQAAAu4AAAAAAAAABAB4")
+ check(mutable.HashMap(1 -> 1))( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuSGFzaE1hcAAAAAAAAAABAwAAeHB3DQAAAu4AAAABAAAABABzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXEAfgAEeA==")
+ check(mutable.HashSet(1, 2, 3))( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuSGFzaFNldAAAAAAAAAABAwAAeHB3DQAAAcIAAAADAAAABQBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJzcQB+AAIAAAADeA==")
+ // TODO SI-8576 Uninitialized field under -Xcheckinit
+ // check(new mutable.History())( "rO0ABXNyACBzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuSGlzdG9yeUhuXxDIFJrsAgACSQAKbWF4SGlzdG9yeUwAA2xvZ3QAIExzY2FsYS9jb2xsZWN0aW9uL211dGFibGUvUXVldWU7eHAAAAPoc3IAHnNjYWxhLmNvbGxlY3Rpb24ubXV0YWJsZS5RdWV1ZbjMURVfOuHHAgAAeHIAJHNjYWxhLmNvbGxlY3Rpb24ubXV0YWJsZS5NdXRhYmxlTGlzdFJpnjJ+gFbAAgADSQADbGVuTAAGZmlyc3QwdAAlTHNjYWxhL2NvbGxlY3Rpb24vbXV0YWJsZS9MaW5rZWRMaXN0O0wABWxhc3QwcQB+AAV4cAAAAABzcgAjc2NhbGEuY29sbGVjdGlvbi5tdXRhYmxlLkxpbmtlZExpc3Sak+nGCZHaUQIAAkwABGVsZW10ABJMamF2YS9sYW5nL09iamVjdDtMAARuZXh0dAAeTHNjYWxhL2NvbGxlY3Rpb24vbXV0YWJsZS9TZXE7eHBwcQB+AApxAH4ACg==")
+ check(mutable.LinkedHashMap(1 -> 2))( "rO0ABXNyACZzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlua2VkSGFzaE1hcAAAAAAAAAABAwAAeHB3DQAAAu4AAAABAAAABABzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJ4")
+ check(mutable.LinkedHashSet(1, 2, 3))( "rO0ABXNyACZzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlua2VkSGFzaFNldAAAAAAAAAABAwAAeHB3DQAAAu4AAAADAAAABABzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4AAgAAAAJzcQB+AAIAAAADeA==")
+ check(mutable.LinkedList(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlua2VkTGlzdJqT6cYJkdpRAgACTAAEZWxlbXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wABG5leHR0AB5Mc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL1NlcTt4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3EAfgAAc3EAfgAEAAAAAnNxAH4AAHNxAH4ABAAAAANzcQB+AABwcQB+AAs=")
+
+ // TODO SI-8576 unstable under -Xcheckinit
+ // check(mutable.ListBuffer(1, 2, 3))( "rO0ABXNyACNzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuTGlzdEJ1ZmZlci9y9I7QyWzGAwAEWgAIZXhwb3J0ZWRJAANsZW5MAAVsYXN0MHQAKUxzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS8kY29sb24kY29sb247TAAqc2NhbGEkY29sbGVjdGlvbiRtdXRhYmxlJExpc3RCdWZmZXIkJHN0YXJ0dAAhTHNjYWxhL2NvbGxlY3Rpb24vaW1tdXRhYmxlL0xpc3Q7eHBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABAAAAAJzcQB+AAQAAAADc3IALHNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLkxpc3RTZXJpYWxpemVFbmQkilxjW/dTC20CAAB4cHcFAAAAAAN4")
+ check(new mutable.StringBuilder(new java.lang.StringBuilder("123")))( "rO0ABXNyACZzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuU3RyaW5nQnVpbGRlcomvqgGv1tTxAgABTAAKdW5kZXJseWluZ3QAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjt4cHNyABdqYXZhLmxhbmcuU3RyaW5nQnVpbGRlcjzV+xRaTGrLAwAAeHB3BAAAAAN1cgACW0OwJmaw4l2ErAIAAHhwAAAAEwAxADIAMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeA==")
+ check(mutable.UnrolledBuffer[Int]())( "rO0ABXNyACdzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuVW5yb2xsZWRCdWZmZXIAAAAAAAAAAQMAAUwAA3RhZ3QAGExzY2FsYS9yZWZsZWN0L0NsYXNzVGFnO3hwc3IAJXNjYWxhLnJlZmxlY3QuTWFuaWZlc3RGYWN0b3J5JCRhbm9uJDnN+aJJU2O1UgIAAHhyABxzY2FsYS5yZWZsZWN0LkFueVZhbE1hbmlmZXN0AAAAAAAAAAECAAFMAAh0b1N0cmluZ3QAEkxqYXZhL2xhbmcvU3RyaW5nO3hwdAADSW50dwQAAAAAeA==")
+
+ import collection.parallel
+ check(parallel.immutable.ParHashMap(1 -> 2))( "rO0ABXNyAC5zY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLmltbXV0YWJsZS5QYXJIYXNoTWFwAAAAAAAAAAECAANMAA9TY2FuTGVhZiRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2NhbkxlYWYkO0wAD1NjYW5Ob2RlJG1vZHVsZXQANUxzY2FsYS9jb2xsZWN0aW9uL3BhcmFsbGVsL1Bhckl0ZXJhYmxlTGlrZSRTY2FuTm9kZSQ7TAAEdHJpZXQAJExzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS9IYXNoTWFwO3hwcHBzcgA1c2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuSGFzaE1hcCRTZXJpYWxpemF0aW9uUHJveHkAAAAAAAAAAgMAAHhwdwQAAAABc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcQB+AAcAAAACeA==")
+ check(parallel.immutable.ParHashSet(1, 2, 3))( "rO0ABXNyAC5zY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLmltbXV0YWJsZS5QYXJIYXNoU2V0AAAAAAAAAAECAANMAA9TY2FuTGVhZiRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2NhbkxlYWYkO0wAD1NjYW5Ob2RlJG1vZHVsZXQANUxzY2FsYS9jb2xsZWN0aW9uL3BhcmFsbGVsL1Bhckl0ZXJhYmxlTGlrZSRTY2FuTm9kZSQ7TAAEdHJpZXQAJExzY2FsYS9jb2xsZWN0aW9uL2ltbXV0YWJsZS9IYXNoU2V0O3hwcHBzcgA1c2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuSGFzaFNldCRTZXJpYWxpemF0aW9uUHJveHkAAAAAAAAAAgMAAHhwdwQAAAADc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcQB+AAcAAAACc3EAfgAHAAAAA3g=")
+ // TODO SI-8576 Uninitialized field under -Xcheckinit
+ // check(new parallel.immutable.ParRange(new Range(0, 1, 2)))( "rO0ABXNyACxzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLmltbXV0YWJsZS5QYXJSYW5nZQAAAAAAAAABAgAETAAXUGFyUmFuZ2VJdGVyYXRvciRtb2R1bGV0AEBMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9pbW11dGFibGUvUGFyUmFuZ2UkUGFyUmFuZ2VJdGVyYXRvciQ7TAAPU2NhbkxlYWYkbW9kdWxldAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA9TY2FuTm9kZSRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2Nhbk5vZGUkO0wABXJhbmdldAAiTHNjYWxhL2NvbGxlY3Rpb24vaW1tdXRhYmxlL1JhbmdlO3hwcHBwc3IAIHNjYWxhLmNvbGxlY3Rpb24uaW1tdXRhYmxlLlJhbmdlabujVKsVMg0CAAdJAANlbmRaAAdpc0VtcHR5SQALbGFzdEVsZW1lbnRJABBudW1SYW5nZUVsZW1lbnRzSQAFc3RhcnRJAARzdGVwSQAPdGVybWluYWxFbGVtZW50eHAAAAABAAAAAAAAAAABAAAAAAAAAAIAAAAC")
+ // TODO SI-8576 unstable under -Xcheckinit
+ // check(parallel.mutable.ParArray(1, 2, 3))( "rO0ABXNyACpzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLm11dGFibGUuUGFyQXJyYXkAAAAAAAAAAQMABEwAF1BhckFycmF5SXRlcmF0b3IkbW9kdWxldAA+THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvbXV0YWJsZS9QYXJBcnJheSRQYXJBcnJheUl0ZXJhdG9yJDtMAA9TY2FuTGVhZiRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2NhbkxlYWYkO0wAD1NjYW5Ob2RlJG1vZHVsZXQANUxzY2FsYS9jb2xsZWN0aW9uL3BhcmFsbGVsL1Bhckl0ZXJhYmxlTGlrZSRTY2FuTm9kZSQ7TAAIYXJyYXlzZXF0ACNMc2NhbGEvY29sbGVjdGlvbi9tdXRhYmxlL0FycmF5U2VxO3hwcHBwc3IAMXNjYWxhLmNvbGxlY3Rpb24ucGFyYWxsZWwubXV0YWJsZS5FeHBvc2VkQXJyYXlTZXGx2OTefAodSQIAAkkABmxlbmd0aFsABWFycmF5dAATW0xqYXZhL2xhbmcvT2JqZWN0O3hyACFzY2FsYS5jb2xsZWN0aW9uLm11dGFibGUuQXJyYXlTZXEVPD3SKEkOcwIAAkkABmxlbmd0aFsABWFycmF5cQB+AAd4cAAAAAN1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAADcHBwAAAAA3VxAH4ACgAAABBzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ADQAAAAJzcQB+AA0AAAADcHBwcHBwcHBwcHBwcHg=")
+ check(parallel.mutable.ParHashMap(1 -> 2))( "rO0ABXNyACxzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLm11dGFibGUuUGFySGFzaE1hcAAAAAAAAAABAwACTAAPU2NhbkxlYWYkbW9kdWxldAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA9TY2FuTm9kZSRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2Nhbk5vZGUkO3hwcHB3DQAAAu4AAAABAAAABAFzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABAAAAAJ4")
+ check(parallel.mutable.ParHashSet(1, 2, 3))( "rO0ABXNyACxzY2FsYS5jb2xsZWN0aW9uLnBhcmFsbGVsLm11dGFibGUuUGFySGFzaFNldAAAAAAAAAABAwACTAAPU2NhbkxlYWYkbW9kdWxldAA1THNjYWxhL2NvbGxlY3Rpb24vcGFyYWxsZWwvUGFySXRlcmFibGVMaWtlJFNjYW5MZWFmJDtMAA9TY2FuTm9kZSRtb2R1bGV0ADVMc2NhbGEvY29sbGVjdGlvbi9wYXJhbGxlbC9QYXJJdGVyYWJsZUxpa2UkU2Nhbk5vZGUkO3hwcHB3DQAAAcIAAAADAAAAGwFzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNxAH4ABAAAAAJzcQB+AAQAAAADeA==")
+
+ check("...".r)("rO0ABXNyABlzY2FsYS51dGlsLm1hdGNoaW5nLlJlZ2V44u3Vap7wIb8CAAJMAAdwYXR0ZXJudAAZTGphdmEvdXRpbC9yZWdleC9QYXR0ZXJuO0wAJXNjYWxhJHV0aWwkbWF0Y2hpbmckUmVnZXgkJGdyb3VwTmFtZXN0ABZMc2NhbGEvY29sbGVjdGlvbi9TZXE7eHBzcgAXamF2YS51dGlsLnJlZ2V4LlBhdHRlcm5GZ9VrbkkCDQIAAkkABWZsYWdzTAAHcGF0dGVybnQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwAAAAAHQAAy4uLnNyADJzY2FsYS5jb2xsZWN0aW9uLmltbXV0YWJsZS5MaXN0JFNlcmlhbGl6YXRpb25Qcm94eQAAAAAAAAABAwAAeHBzcgAsc2NhbGEuY29sbGVjdGlvbi5pbW11dGFibGUuTGlzdFNlcmlhbGl6ZUVuZCSKXGNb91MLbQIAAHhweA==",
+ r => (r.toString))
+}
diff --git a/test/files/run/t8549b.scala b/test/files/run/t8549b.scala
new file mode 100644
index 0000000000..1e1bf2c0bc
--- /dev/null
+++ b/test/files/run/t8549b.scala
@@ -0,0 +1,16 @@
+
+@SerialVersionUID(42)
+class C
+
+@SerialVersionUID(43 - 1)
+class D
+
+
+object Test extends App {
+ def checkId(cls: Class[_]) {
+ val id = cls.getDeclaredField("serialVersionUID").get(null)
+ assert(id == 42, (cls, id))
+ }
+ checkId(classOf[C])
+ checkId(classOf[D])
+}
diff --git a/test/files/run/t8570.flags b/test/files/run/t8570.flags
new file mode 100644
index 0000000000..3d1ee4760a
--- /dev/null
+++ b/test/files/run/t8570.flags
@@ -0,0 +1 @@
+-Xcheckinit
diff --git a/test/files/run/t8570.scala b/test/files/run/t8570.scala
new file mode 100644
index 0000000000..bbe83e9080
--- /dev/null
+++ b/test/files/run/t8570.scala
@@ -0,0 +1,10 @@
+trait Trait40_1 {
+ val value37_2 = ()
+ def run = { value37_2 }
+}
+
+object Test {
+ def main(args: Array[String]) {
+ (new Trait40_1 {}).run
+ }
+}
diff --git a/test/files/run/t8570a.check b/test/files/run/t8570a.check
new file mode 100644
index 0000000000..6a452c185a
--- /dev/null
+++ b/test/files/run/t8570a.check
@@ -0,0 +1 @@
+()
diff --git a/test/files/run/t8570a.flags b/test/files/run/t8570a.flags
new file mode 100644
index 0000000000..3d1ee4760a
--- /dev/null
+++ b/test/files/run/t8570a.flags
@@ -0,0 +1 @@
+-Xcheckinit
diff --git a/test/files/run/t8570a.scala b/test/files/run/t8570a.scala
new file mode 100644
index 0000000000..ef116e2a8a
--- /dev/null
+++ b/test/files/run/t8570a.scala
@@ -0,0 +1,14 @@
+trait Trait40_1 {
+ val value37_2 = ()
+ def run = { value37_2 }
+}
+
+trait T1 extends Trait40_1 {
+ override val value37_2 = ()
+}
+
+object Test {
+ def main(args: Array[String]) {
+ println((new T1 {}).run)
+ }
+}
diff --git a/test/files/run/t8574.scala b/test/files/run/t8574.scala
new file mode 100644
index 0000000000..8c23ada482
--- /dev/null
+++ b/test/files/run/t8574.scala
@@ -0,0 +1,27 @@
+import annotation._
+
+@SerialVersionUID(42) @strictfp class Foo[@specialized(Int) T] extends Serializable {
+ def foo(t: T) = t
+}
+
+object Test extends App {
+ def checkUID(cls: Class[_], expected: Long) = {
+ val actual = java.io.ObjectStreamClass.lookup(cls).getSerialVersionUID
+ assert(actual == expected, s"$actual != expected for ${cls}")
+ }
+ def checkStrictFp(cls: Class[_]) = {
+ import java.lang.reflect._
+ for (m <- cls.getDeclaredMethods) {
+ val isStrict = Modifier.isStrict(m.getModifiers)
+ assert(isStrict, cls)
+ }
+ }
+ def check(x: AnyRef) {
+ checkUID(x.getClass, 42)
+ checkStrictFp(x.getClass)
+ }
+
+ check(new Foo[String])
+ check(new Foo[Int])
+}
+
diff --git a/test/files/run/t8601-closure-elim.flags b/test/files/run/t8601-closure-elim.flags
new file mode 100644
index 0000000000..49d036a887
--- /dev/null
+++ b/test/files/run/t8601-closure-elim.flags
@@ -0,0 +1 @@
+-optimize
diff --git a/test/files/run/t8601-closure-elim.scala b/test/files/run/t8601-closure-elim.scala
new file mode 100644
index 0000000000..2c5b03af77
--- /dev/null
+++ b/test/files/run/t8601-closure-elim.scala
@@ -0,0 +1,26 @@
+import scala.tools.partest.BytecodeTest
+import scala.tools.asm
+import scala.tools.asm.util._
+import scala.collection.JavaConverters._
+
+object Test extends BytecodeTest {
+ val nullChecks = Set(asm.Opcodes.NEW)
+
+ def show: Unit = {
+ def test(methodName: String) {
+ val classNode = loadClassNode("Foo")
+ val methodNode = getMethod(classNode, "b")
+ val ops = methodNode.instructions.iterator.asScala.map(_.getOpcode).toList
+ assert(!ops.contains(asm.Opcodes.NEW), ops)// should be allocation free if the closure is eliminiated
+ }
+ test("b")
+ }
+}
+
+class Foo {
+ @inline final def a(x: Int => Int) = x(1)
+ final def b {
+ val delta = 0
+ a(x => delta + 1)
+ }
+}
diff --git a/test/files/run/t8601.flags b/test/files/run/t8601.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601.scala b/test/files/run/t8601.scala
new file mode 100644
index 0000000000..e1afc23cc4
--- /dev/null
+++ b/test/files/run/t8601.scala
@@ -0,0 +1,15 @@
+object Test {
+ def idiv(x: Int): Unit = x / 0
+ def ldiv(x: Long): Unit = x / 0
+ def irem(x: Int): Unit = x % 0
+ def lrem(x: Long): Unit = x % 0
+
+ def check(x: => Any) = try { x; sys.error("failed to throw divide by zero!") } catch { case _: ArithmeticException => }
+
+ def main(args: Array[String]) {
+ check(idiv(1))
+ check(ldiv(1L))
+ check(irem(1))
+ check(lrem(1L))
+ }
+}
diff --git a/test/files/run/t8601b.flags b/test/files/run/t8601b.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601b.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601b.scala b/test/files/run/t8601b.scala
new file mode 100644
index 0000000000..9c37ce33d6
--- /dev/null
+++ b/test/files/run/t8601b.scala
@@ -0,0 +1,14 @@
+object Test {
+ def len(x: Array[String]): Unit = x.length
+ def load(x: Array[String]): Unit = x(0)
+ def newarray(i: Int): Unit = new Array[Int](i)
+
+ def check(x: => Any) = try { x; sys.error("failed to throw NPE!") } catch { case _: NullPointerException => }
+ def checkNegSize(x: => Any) = try { x; sys.error("failed to throw NegativeArraySizeException!") } catch { case _: NegativeArraySizeException => }
+
+ def main(args: Array[String]) {
+ check(len(null)) // bug: did not NPE
+ check(load(null))
+ checkNegSize(newarray(-1))
+ }
+}
diff --git a/test/files/run/t8601c.flags b/test/files/run/t8601c.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601c.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601c.scala b/test/files/run/t8601c.scala
new file mode 100644
index 0000000000..c487d6825e
--- /dev/null
+++ b/test/files/run/t8601c.scala
@@ -0,0 +1,12 @@
+object Test {
+ def loadField(x: scala.runtime.IntRef): Unit = x.elem
+ def storeField(x: scala.runtime.IntRef): Unit = x.elem = 42
+
+ def check(x: => Any) = try { x; sys.error("failed to throw NPE!") } catch { case _: NullPointerException => }
+
+ def main(args: Array[String]) {
+ check(loadField(null)) // bug: did not NPE under -Ydead-code
+ check(storeField(null))
+
+ }
+}
diff --git a/test/files/run/t8601d.flags b/test/files/run/t8601d.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601d.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601d.scala b/test/files/run/t8601d.scala
new file mode 100644
index 0000000000..ac89963d67
--- /dev/null
+++ b/test/files/run/t8601d.scala
@@ -0,0 +1,8 @@
+object Test {
+ def monitor(x: AnyRef): Unit = {x.synchronized(()); ()}
+ def check(x: => Any) = try { x; sys.error("failed to throw NPE") } catch { case _: NullPointerException => }
+
+ def main(args: Array[String]) {
+ check(monitor(null))
+ }
+}
diff --git a/test/files/run/t8601e.flags b/test/files/run/t8601e.flags
new file mode 100644
index 0000000000..49d036a887
--- /dev/null
+++ b/test/files/run/t8601e.flags
@@ -0,0 +1 @@
+-optimize
diff --git a/test/files/run/t8601e/StaticInit.class b/test/files/run/t8601e/StaticInit.class
new file mode 100644
index 0000000000..99a0e2a643
--- /dev/null
+++ b/test/files/run/t8601e/StaticInit.class
Binary files differ
diff --git a/test/files/run/t8601e/StaticInit.java b/test/files/run/t8601e/StaticInit.java
new file mode 100644
index 0000000000..7543ed98b8
--- /dev/null
+++ b/test/files/run/t8601e/StaticInit.java
@@ -0,0 +1,8 @@
+public class StaticInit {
+ static {
+ if ("".isEmpty()) {
+ throw new RuntimeException();
+ }
+ }
+ public static int fld = 42;
+}
diff --git a/test/files/run/t8601e/Test.scala b/test/files/run/t8601e/Test.scala
new file mode 100644
index 0000000000..838114f6a7
--- /dev/null
+++ b/test/files/run/t8601e/Test.scala
@@ -0,0 +1,12 @@
+class C {
+ def foo: Unit = {StaticInit.fld}
+}
+
+object Test extends App {
+ try {
+ new C().foo
+ sys.error("StaticInit.<clinit> was not run!")
+ } catch {
+ case t: ExceptionInInitializerError =>
+ }
+}
diff --git a/test/files/run/virtpatmat_staging.flags b/test/files/run/virtpatmat_staging.flags
index 48fd867160..0a22f7c729 100644
--- a/test/files/run/virtpatmat_staging.flags
+++ b/test/files/run/virtpatmat_staging.flags
@@ -1 +1,2 @@
+-Yrangepos:false
-Xexperimental
diff --git a/test/junit/scala/StringContextTest.scala b/test/junit/scala/StringContextTest.scala
new file mode 100644
index 0000000000..5abfe90cd1
--- /dev/null
+++ b/test/junit/scala/StringContextTest.scala
@@ -0,0 +1,51 @@
+
+package scala
+
+import org.junit.Test
+import org.junit.Assert._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil._
+
+@RunWith(classOf[JUnit4])
+class StringContextTest {
+
+ import StringContext._
+
+ @Test def noEscape() = {
+ val s = "string"
+ val res = processEscapes(s)
+ assertEquals(s, res)
+ }
+ @Test def tabbed() = {
+ val s = """a\tb"""
+ val res = processEscapes(s)
+ assertEquals("a\tb", res)
+ }
+ @Test def quoted() = {
+ val s = """hello, \"world\""""
+ val res = processEscapes(s)
+ assertEquals("""hello, "world"""", res)
+ }
+ @Test def octal() = {
+ val s = """\123cala"""
+ val res = treatEscapes(s)
+ assertEquals("Scala", res)
+ }
+ @Test def doubled() = {
+ val s = """\123cala\123yntax"""
+ val res = treatEscapes(s)
+ assertEquals("ScalaSyntax", res)
+ }
+ @Test def badly() = assertThrows[InvalidEscapeException] {
+ val s = """Scala\"""
+ val res = treatEscapes(s)
+ assertEquals("Scala", res)
+ }
+ @Test def noOctal() = assertThrows[InvalidEscapeException] {
+ val s = """\123cala"""
+ val res = processEscapes(s)
+ assertEquals("Scala", res)
+ }
+}
diff --git a/test/junit/scala/collection/convert/MapWrapperTest.scala b/test/junit/scala/collection/convert/MapWrapperTest.scala
index 060b6b5937..22eaf858ea 100644
--- a/test/junit/scala/collection/convert/MapWrapperTest.scala
+++ b/test/junit/scala/collection/convert/MapWrapperTest.scala
@@ -46,4 +46,14 @@ class MapWrapperTest {
assertFalse(javaMap.containsKey(null)) // negative test, null key
assertEquals(4, scalaMap.containsCounter)
}
+
+ // test for SI-8504
+ @Test
+ def testHashCode() {
+ import scala.collection.JavaConverters._
+ val javaMap = Map(1 -> null).asJava
+
+ // Before the fix for SI-8504, this throws a NPE
+ javaMap.hashCode
+ }
}
diff --git a/test/junit/scala/reflect/internal/ScopeTest.scala b/test/junit/scala/reflect/internal/ScopeTest.scala
new file mode 100644
index 0000000000..5166620189
--- /dev/null
+++ b/test/junit/scala/reflect/internal/ScopeTest.scala
@@ -0,0 +1,54 @@
+package symtab
+
+import scala.tools.nsc.symtab
+
+import org.junit.Assert._
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil.assertThrows
+import scala.tools.nsc.symtab.SymbolTableForUnitTesting
+
+@RunWith(classOf[JUnit4])
+class ScopeTest {
+ object symbolTable extends SymbolTableForUnitTesting
+
+ import symbolTable._
+
+ @Test
+ def testNestedScopeSmall(): Unit = testNestedScope(0)
+ @Test
+ def testNestedScopeLarge(): Unit = testNestedScope(64) // exceeding MIN_HASH
+
+ private def testNestedScope(initSize: Int) {
+ def sym(termName: String): Symbol = NoSymbol.newValue(TermName(termName))
+ val foo = sym("foo")
+ val bar = sym("bar")
+
+ val outerElems = List.tabulate(initSize)(i => sym(i.toString))
+ val outer = newScopeWith(outerElems ++ List(foo, bar) : _*)
+ assertTrue(outer.containsName(foo.name))
+ assertTrue(outer.containsName(bar.name))
+
+ val baz = sym("baz")
+ val nested = newNestedScope(outer)
+
+ // Entries from the outer scope are entered in the nested.
+ assertTrue(outer.containsName(foo.name))
+ assertTrue(outer.containsName(bar.name))
+
+ // Nested scopes structurally share ScopeEntry-s with the outer.
+ assertSame(outer.lookupEntry(foo.name), nested.lookupEntry(foo.name))
+ nested.enter(baz)
+
+ // Symbols entered in the nested scope aren't visible in the outer.
+ assertTrue(nested.containsName(baz.name))
+ assertTrue(!outer.containsName(baz.name))
+
+ // Unlinking a symbol in the inner scope doesn't modify the outer
+ nested.unlink(bar)
+ assert(!nested.containsName(bar.name))
+ assert(outer.containsName(bar.name))
+ }
+}
diff --git a/test/scaladoc/run/SI-8479.check b/test/scaladoc/run/SI-8479.check
new file mode 100644
index 0000000000..619c56180b
--- /dev/null
+++ b/test/scaladoc/run/SI-8479.check
@@ -0,0 +1 @@
+Done.
diff --git a/test/scaladoc/run/SI-8479.scala b/test/scaladoc/run/SI-8479.scala
new file mode 100755
index 0000000000..3c91395025
--- /dev/null
+++ b/test/scaladoc/run/SI-8479.scala
@@ -0,0 +1,32 @@
+import scala.tools.nsc.doc.model._
+import scala.tools.nsc.doc.base._
+import scala.tools.nsc.doc.base.comment._
+import scala.tools.partest.ScaladocModelTest
+import java.net.{URI, URL}
+import java.io.File
+
+object Test extends ScaladocModelTest {
+
+ override def code =
+ """
+ |object Test {
+ | val x = new SparkContext(master = "")
+ |}
+ |
+ |class SparkContext(config: Any) {
+ |
+ | /** Scaladoc comment */
+ | def this(
+ | master: String,
+ | appName: String = "") = this(null)
+ |}
+ |
+ |
+ """.stripMargin
+
+ override def scaladocSettings = ""
+
+ def testModel(rootPackage: Package) {
+ // it didn't crash
+ }
+}
diff --git a/versions.properties b/versions.properties
index 0e56f731ed..1212734d22 100644
--- a/versions.properties
+++ b/versions.properties
@@ -1,10 +1,10 @@
-#Wed, 16 Apr 2014 11:13:08 +0200
+#Tue, 20 May 2014 10:01:37 +0200
# NOTE: this file determines the content of the scala-distribution
# via scala-dist-pom.xml and scala-library-all-pom.xml
# when adding new properties that influence a release,
# also add them to the update.versions mechanism in build.xml,
# which is used by scala-release-2.11.x in scala/jenkins-scripts
-starr.version=2.11.0
+starr.version=2.11.1
starr.use.released=1
# These are the versions of the modules that go with this release.
@@ -14,15 +14,15 @@ starr.use.released=1
scala.binary.version=2.11
# e.g. 2.11.0-RC1, 2.11.0, 2.11.1-RC1, 2.11.1
# this defines the dependency on scala-continuations-plugin in scala-dist's pom
-scala.full.version=2.11.0
+scala.full.version=2.11.1
# external modules shipped with distribution, as specified by scala-library-all's pom
-scala-xml.version.number=1.0.1
+scala-xml.version.number=1.0.2
scala-parser-combinators.version.number=1.0.1
-scala-continuations-plugin.version.number=1.0.1
-scala-continuations-library.version.number=1.0.1
+scala-continuations-plugin.version.number=1.0.2
+scala-continuations-library.version.number=1.0.2
scala-swing.version.number=1.0.1
-akka-actor.version.number=2.3.2
+akka-actor.version.number=2.3.3
actors-migration.version.number=1.1.0
# external modules, used internally (not shipped)