diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 58 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaScanners.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/StdNames.scala | 2 | ||||
-rw-r--r-- | test/files/run/t3236/AnnotationTest.scala | 33 | ||||
-rw-r--r-- | test/files/run/t3236/BooleanAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/ByteAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/CharAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/Constants.java | 34 | ||||
-rw-r--r-- | test/files/run/t3236/DoubleAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/FloatAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/IntAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/LongAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/ShortAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/StringAnnotation.java | 7 | ||||
-rw-r--r-- | test/files/run/t3236/Test.scala | 44 |
15 files changed, 234 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index eb25eb6e06..bc1c19237a 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -567,10 +567,64 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName): ValDef = { val tpt1 = optArrayBrackets(tpt) - if (in.token == EQUALS && !mods.isParameter) skipTo(COMMA, SEMI) + + /** Tries to detect final static literals syntactically and returns a constant type replacement */ + def optConstantTpe(): Tree = { + in.nextToken() + + def constantTpe(lit: Any): Tree = + try TypeTree(ConstantType(Constant(lit))) + finally in.nextToken() + + def byType(value: Long): Tree = + tpt.tpe match { + case ByteTpe => constantTpe(value.toByte) + case CharTpe => constantTpe(value.toChar) + case ShortTpe => constantTpe(value.toShort) + case IntTpe => constantTpe(value.toInt) + case LongTpe => constantTpe(value.toLong) + case _ => tpt1 + } + + if (mods.hasFlag(Flags.STATIC) && mods.isFinal) { + def lit(negate: Boolean): Tree = + if (in.lookaheadToken == SEMI) + in.token match { + case TRUE if tpt.tpe == BooleanTpe => constantTpe(!negate) + case FALSE if tpt.tpe == BooleanTpe => constantTpe(negate) + case CHARLIT => byType(in.name.charAt(0)) + case INTLIT => byType(in.intVal(negate)) + case LONGLIT if tpt.tpe == LongTpe => constantTpe(in.intVal(negate)) + case FLOATLIT if tpt.tpe == FloatTpe => constantTpe(in.floatVal(negate).toFloat) + case DOUBLELIT if tpt.tpe == DoubleTpe => constantTpe(in.floatVal(negate)) + case STRINGLIT => + tpt match { + case Ident(TypeName("String")) => constantTpe(in.name.toString) + case _ => tpt1 + } + case _ => tpt1 + } + else tpt1 + + in.token match { + case MINUS | BANG => + in.nextToken() + lit(negate = true) + case other => lit(negate = false) + } + } else tpt1 + } + + val tpt2: Tree = + if (in.token == EQUALS && !mods.isParameter) { + val res = optConstantTpe() + skipTo(COMMA, SEMI) + res + } else tpt1 + val mods1 = if (mods.isFinal) mods &~ Flags.FINAL else mods | Flags.MUTABLE atPos(pos) { - ValDef(mods1, name, tpt1, blankExpr) + ValDef(mods1, name, tpt2, blankExpr) } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index ac86dfd665..94c9d07939 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -89,6 +89,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { javanme.ELSEkw -> ELSE, javanme.ENUMkw -> ENUM, javanme.EXTENDSkw -> EXTENDS, + javanme.FALSEkw -> FALSE, javanme.FINALkw -> FINAL, javanme.FINALLYkw -> FINALLY, javanme.FLOATkw -> FLOAT, @@ -118,6 +119,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { javanme.THROWkw -> THROW, javanme.THROWSkw -> THROWS, javanme.TRANSIENTkw -> TRANSIENT, + javanme.TRUEkw -> TRUE, javanme.TRYkw -> TRY, javanme.VOIDkw -> VOID, javanme.VOLATILEkw -> VOLATILE, diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index a0688e129c..5e2bbf9598 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -1103,6 +1103,7 @@ trait StdNames { final val ELSEkw: TermName = kw("else") final val ENUMkw: TermName = kw("enum") final val EXTENDSkw: TermName = kw("extends") + final val FALSEkw: TermName = kw("false") final val FINALkw: TermName = kw("final") final val FINALLYkw: TermName = kw("finally") final val FLOATkw: TermName = kw("float") @@ -1132,6 +1133,7 @@ trait StdNames { final val THROWkw: TermName = kw("throw") final val THROWSkw: TermName = kw("throws") final val TRANSIENTkw: TermName = kw("transient") + final val TRUEkw: TermName = kw("true") final val TRYkw: TermName = kw("try") final val VOIDkw: TermName = kw("void") final val VOLATILEkw: TermName = kw("volatile") diff --git a/test/files/run/t3236/AnnotationTest.scala b/test/files/run/t3236/AnnotationTest.scala new file mode 100644 index 0000000000..c2f9ae7837 --- /dev/null +++ b/test/files/run/t3236/AnnotationTest.scala @@ -0,0 +1,33 @@ +trait AnnotationTest { + @BooleanAnnotation(Constants.BooleanTrue) + @ByteAnnotation(Constants.Byte) + @CharAnnotation(Constants.Char) + @ShortAnnotation(Constants.Short) + @IntAnnotation(Constants.Int) + @LongAnnotation(Constants.Long) + @FloatAnnotation(Constants.Float) + @DoubleAnnotation(Constants.Double) + @StringAnnotation(Constants.String) + def test1: Unit + + @BooleanAnnotation(Constants.InvertedBoolean) + @ByteAnnotation(Constants.NegativeByte) + @ShortAnnotation(Constants.NegativeShort) + @IntAnnotation(Constants.NegativeInt) + @LongAnnotation(Constants.NegativeLong) + @FloatAnnotation(Constants.NegativeFloat) + @DoubleAnnotation(Constants.NegativeDouble) + @StringAnnotation(Constants.NegativeString) + def test2: Unit + + @BooleanAnnotation(Constants.BooleanFalse) + @ByteAnnotation(Constants.LiteralCharAsByte) + @CharAnnotation(Constants.LiteralChar) + @ShortAnnotation(Constants.LiteralCharAsShort) + @IntAnnotation(Constants.LiteralCharAsInt) + @LongAnnotation(Constants.LiteralCharAsLong) + def test3: Unit + + @LongAnnotation(Constants.LiteralIntAsLong) + def test4: Unit +} diff --git a/test/files/run/t3236/BooleanAnnotation.java b/test/files/run/t3236/BooleanAnnotation.java new file mode 100644 index 0000000000..7e57a5e0db --- /dev/null +++ b/test/files/run/t3236/BooleanAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface BooleanAnnotation { + boolean value(); +} diff --git a/test/files/run/t3236/ByteAnnotation.java b/test/files/run/t3236/ByteAnnotation.java new file mode 100644 index 0000000000..c986fa5d27 --- /dev/null +++ b/test/files/run/t3236/ByteAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface ByteAnnotation { + byte value(); +} diff --git a/test/files/run/t3236/CharAnnotation.java b/test/files/run/t3236/CharAnnotation.java new file mode 100644 index 0000000000..1715f1b7de --- /dev/null +++ b/test/files/run/t3236/CharAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface CharAnnotation { + char value(); +} diff --git a/test/files/run/t3236/Constants.java b/test/files/run/t3236/Constants.java new file mode 100644 index 0000000000..16b4001f76 --- /dev/null +++ b/test/files/run/t3236/Constants.java @@ -0,0 +1,34 @@ +public class Constants { + public static final boolean BooleanTrue = true; + public static final boolean BooleanFalse = false; + public static final boolean InvertedBoolean = !true; + + public static final byte Byte = 23; + public static final byte NegativeByte = -42; + public static final byte LiteralCharAsByte = 'a'; + + public static final char Char = 33; + public static final char LiteralChar = 'b'; + + public static final short Short = 0x1234; + public static final short NegativeShort= -0x5678; + public static final short LiteralCharAsShort = 'c'; + + public static final int Int = 0xabcdef; + public static final int NegativeInt = -12345678; + public static final int LiteralCharAsInt = 'd'; + + public static final long Long = 0x1234567890abcdefL; + public static final long NegativeLong = -0xfedcba09876L; + public static final long LiteralCharAsLong = 'e'; + public static final long LiteralIntAsLong = 0x12345678; + + public static final float Float = 42.232323f; + public static final float NegativeFloat = -3.1415f; + + public static final double Double = 23.4243598374594d; + public static final double NegativeDouble = -42.2324358934589734859d; + + public static final String String = "testConstant"; + public static final String NegativeString = "!#!$!grml%!%!$#@@@"; +} diff --git a/test/files/run/t3236/DoubleAnnotation.java b/test/files/run/t3236/DoubleAnnotation.java new file mode 100644 index 0000000000..1eb8223f4e --- /dev/null +++ b/test/files/run/t3236/DoubleAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface DoubleAnnotation { + double value(); +} diff --git a/test/files/run/t3236/FloatAnnotation.java b/test/files/run/t3236/FloatAnnotation.java new file mode 100644 index 0000000000..c723a25fad --- /dev/null +++ b/test/files/run/t3236/FloatAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface FloatAnnotation { + float value(); +} diff --git a/test/files/run/t3236/IntAnnotation.java b/test/files/run/t3236/IntAnnotation.java new file mode 100644 index 0000000000..2ffad8890c --- /dev/null +++ b/test/files/run/t3236/IntAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface IntAnnotation { + int value(); +} diff --git a/test/files/run/t3236/LongAnnotation.java b/test/files/run/t3236/LongAnnotation.java new file mode 100644 index 0000000000..9f80b41398 --- /dev/null +++ b/test/files/run/t3236/LongAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface LongAnnotation { + long value(); +} diff --git a/test/files/run/t3236/ShortAnnotation.java b/test/files/run/t3236/ShortAnnotation.java new file mode 100644 index 0000000000..f0a35892c7 --- /dev/null +++ b/test/files/run/t3236/ShortAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface ShortAnnotation { + short value(); +} diff --git a/test/files/run/t3236/StringAnnotation.java b/test/files/run/t3236/StringAnnotation.java new file mode 100644 index 0000000000..0fdc1ead38 --- /dev/null +++ b/test/files/run/t3236/StringAnnotation.java @@ -0,0 +1,7 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface StringAnnotation { + String value(); +} diff --git a/test/files/run/t3236/Test.scala b/test/files/run/t3236/Test.scala new file mode 100644 index 0000000000..7e351e0b6b --- /dev/null +++ b/test/files/run/t3236/Test.scala @@ -0,0 +1,44 @@ +import scala.language.reflectiveCalls + +object Test extends App { + val theClass = classOf[AnnotationTest] + + def annotation[T <: java.lang.annotation.Annotation](annotationClass: Class[T], methodName: String): T = + theClass.getDeclaredMethod(methodName) + .getAnnotation[T](annotationClass) + + def check[T, U <: java.lang.annotation.Annotation { def value(): T } ](annotationClass: Class[U], methodName: String, expected: T): Unit = { + val a = annotation(annotationClass, methodName) + assert(a != null, s"No annotation of type $annotationClass found on method $methodName") + assert(a.value() == expected, s"Actual value of annotation $a on $methodName was not of expected value $expected") + } + + check(classOf[BooleanAnnotation], "test1", Constants.BooleanTrue) + check(classOf[ByteAnnotation], "test1", Constants.Byte) + check(classOf[CharAnnotation], "test1", Constants.Char) + check(classOf[ShortAnnotation], "test1", Constants.Short) + check(classOf[IntAnnotation], "test1", Constants.Int) + check(classOf[LongAnnotation], "test1", Constants.Long) + check(classOf[FloatAnnotation], "test1", Constants.Float) + check(classOf[DoubleAnnotation], "test1", Constants.Double) + check(classOf[StringAnnotation], "test1", Constants.String) + + check(classOf[BooleanAnnotation], "test2", Constants.InvertedBoolean) + check(classOf[ByteAnnotation], "test2", Constants.NegativeByte) + // no negative char possible + check(classOf[ShortAnnotation], "test2", Constants.NegativeShort) + check(classOf[IntAnnotation], "test2", Constants.NegativeInt) + check(classOf[LongAnnotation], "test2", Constants.NegativeLong) + check(classOf[FloatAnnotation], "test2", Constants.NegativeFloat) + check(classOf[DoubleAnnotation], "test2", Constants.NegativeDouble) + check(classOf[StringAnnotation], "test2", Constants.NegativeString) + + check(classOf[BooleanAnnotation], "test3", Constants.BooleanFalse) + check(classOf[ByteAnnotation], "test3", Constants.LiteralCharAsByte) + check(classOf[CharAnnotation], "test3", Constants.LiteralChar) + check(classOf[ShortAnnotation], "test3", Constants.LiteralCharAsShort) + check(classOf[IntAnnotation], "test3", Constants.LiteralCharAsInt) + check(classOf[LongAnnotation], "test3", Constants.LiteralCharAsLong) + + check(classOf[LongAnnotation], "test4", Constants.LiteralIntAsLong) +} |