From 77b8b6a11fbcb067160052a54b9d777593787fb5 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Wed, 15 Jul 2015 19:59:57 +0200 Subject: SI-9393 fix modifiers of ClassBTypes for Java annotations The Scala classfile and java source parsers make Java annotation classes (which are actually interfaces at the classfile level) look like Scala annotation classes: - the INTERFACE / ABSTRACT flags are not added - scala.annotation.Annotation is added as superclass - scala.annotation.ClassfileAnnotation is added as interface This makes type-checking @Annot uniform, whether it is defined in Java or Scala. This is a hack that leads to various bugs (SI-9393, SI-9400). Instead the type-checking should be special-cased for Java annotations. This commit fixes SI-9393 and a part of SI-9400, but it's still easy to generate invalid classfiles. Restores the assertions that were disabled in #4621. I'd like to leave these assertions in: they are valuable and helped uncovering the issue being fixed here. A new flag JAVA_ANNOTATION is introduced for Java annotation ClassSymbols, similar to the existing ENUM flag. When building ClassBTypes for Java annotations, the flags, superclass and interfaces are recovered to represent the situation in the classfile. Cleans up and documents the flags space in the area of "late" and "anti" flags. The test for SI-9393 is extended to test both the classfile and the java source parser. --- .../tools/nsc/backend/jvm/BCodeAsmCommon.scala | 20 ++++- .../tools/nsc/backend/jvm/BCodeSkelBuilder.scala | 6 +- .../scala/tools/nsc/backend/jvm/BTypes.scala | 21 +++-- .../tools/nsc/backend/jvm/BTypesFromSymbols.scala | 13 +++- .../scala/tools/nsc/javac/JavaParsers.scala | 2 +- .../reflect/internal/ClassfileConstants.scala | 2 + src/reflect/scala/reflect/internal/Flags.scala | 33 ++++++-- src/reflect/scala/reflect/internal/HasFlags.scala | 1 + src/reflect/scala/reflect/internal/Symbols.scala | 2 +- test/files/jvm/innerClassAttribute/Test.scala | 4 +- test/files/pos/t9393/Named.java | 3 - test/files/pos/t9393/NamedImpl.java | 15 ---- test/files/pos/t9393/NamedImpl_1.java | 15 ++++ test/files/pos/t9393/NamedImpl_2.java | 15 ++++ test/files/pos/t9393/Named_1.java | 3 + test/files/pos/t9393/Named_2.java | 3 + test/files/pos/t9393/test.scala | 3 - test/files/pos/t9393/test_2.scala | 4 + test/junit/scala/tools/nsc/symtab/FlagsTest.scala | 89 ++++++++++++++++++++++ 19 files changed, 201 insertions(+), 53 deletions(-) delete mode 100644 test/files/pos/t9393/Named.java delete mode 100644 test/files/pos/t9393/NamedImpl.java create mode 100644 test/files/pos/t9393/NamedImpl_1.java create mode 100644 test/files/pos/t9393/NamedImpl_2.java create mode 100644 test/files/pos/t9393/Named_1.java create mode 100644 test/files/pos/t9393/Named_2.java delete mode 100644 test/files/pos/t9393/test.scala create mode 100644 test/files/pos/t9393/test_2.scala create mode 100644 test/junit/scala/tools/nsc/symtab/FlagsTest.scala diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala index dec5adc9aa..f14ca0f40b 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala @@ -256,6 +256,9 @@ final class BCodeAsmCommon[G <: Global](val global: G) { if (hasAbstractMethod) ACC_ABSTRACT else 0 } GenBCode.mkFlags( + // SI-9393: the classfile / java source parser make java annotation symbols look like classes. + // here we recover the actual classfile flags. + if (classSym.hasJavaAnnotationFlag) ACC_ANNOTATION | ACC_INTERFACE | ACC_ABSTRACT else 0, if (classSym.isPublic) ACC_PUBLIC else 0, if (classSym.isFinal) ACC_FINAL else 0, // see the link above. javac does the same: ACC_SUPER for all classes, but not interfaces. @@ -310,10 +313,10 @@ final class BCodeAsmCommon[G <: Global](val global: G) { } private def retentionPolicyOf(annot: AnnotationInfo): Symbol = - annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr).map(_.assocs).map(assoc => + annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr).map(_.assocs).flatMap(assoc => assoc.collectFirst { case (`nme`.value, LiteralAnnotArg(Constant(value: Symbol))) => value - }).flatten.getOrElse(AnnotationRetentionPolicyClassValue) + }).getOrElse(AnnotationRetentionPolicyClassValue) def implementedInterfaces(classSym: Symbol): List[Symbol] = { // Additional interface parents based on annotations and other cues @@ -322,9 +325,18 @@ final class BCodeAsmCommon[G <: Global](val global: G) { case _ => None } - def isInterfaceOrTrait(sym: Symbol) = sym.isInterface || sym.isTrait + // SI-9393: java annotations are interfaces, but the classfile / java source parsers make them look like classes. + def isInterfaceOrTrait(sym: Symbol) = sym.isInterface || sym.isTrait || sym.hasJavaAnnotationFlag - val allParents = classSym.info.parents ++ classSym.annotations.flatMap(newParentForAnnotation) + val classParents = { + val parents = classSym.info.parents + // SI-9393: the classfile / java source parsers add Annotation and ClassfileAnnotation to the + // parents of a java annotations. undo this for the backend (where we need classfile-level information). + if (classSym.hasJavaAnnotationFlag) parents.filterNot(c => c.typeSymbol == ClassfileAnnotationClass || c.typeSymbol == AnnotationClass) + else parents + } + + val allParents = classParents ++ classSym.annotations.flatMap(newParentForAnnotation) // We keep the superClass when computing minimizeParents to eliminate more interfaces. // Example: T can be eliminated from D diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index d2d510e8a9..2297faab6a 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -153,9 +153,9 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { */ private def initJClass(jclass: asm.ClassVisitor) { - val ps = claszSymbol.info.parents - val superClass: String = if (ps.isEmpty) ObjectReference.internalName else internalName(ps.head.typeSymbol) - val interfaceNames = classBTypeFromSymbol(claszSymbol).info.get.interfaces map { + val bType = classBTypeFromSymbol(claszSymbol) + val superClass = bType.info.get.superClass.getOrElse(ObjectReference).internalName + val interfaceNames = bType.info.get.interfaces map { case classBType => if (classBType.isNestedClass.get) { innerClassBufferASM += classBType } classBType.internalName diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index 9bae63f1fc..8720da84e8 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -841,17 +841,16 @@ abstract class BTypes { assert(!ClassBType.isInternalPhantomType(internalName), s"Cannot create ClassBType for phantom type $this") - // TODO bring these back in a way that doesn't trip pos/t9393 - // assert( - // if (info.get.superClass.isEmpty) { isJLO(this) || (isCompilingPrimitive && ClassBType.hasNoSuper(internalName)) } - // else if (isInterface.get) isJLO(info.get.superClass.get) - // else !isJLO(this) && ifInit(info.get.superClass.get)(!_.isInterface.get), - // s"Invalid superClass in $this: ${info.get.superClass}" - // ) - // assert( - // info.get.interfaces.forall(c => ifInit(c)(_.isInterface.get)), - // s"Invalid interfaces in $this: ${info.get.interfaces}" - // ) + assert( + if (info.get.superClass.isEmpty) { isJLO(this) || (isCompilingPrimitive && ClassBType.hasNoSuper(internalName)) } + else if (isInterface.get) isJLO(info.get.superClass.get) + else !isJLO(this) && ifInit(info.get.superClass.get)(!_.isInterface.get), + s"Invalid superClass in $this: ${info.get.superClass}" + ) + assert( + info.get.interfaces.forall(c => ifInit(c)(_.isInterface.get)), + s"Invalid interfaces in $this: ${info.get.interfaces}" + ) assert(info.get.nestedClasses.forall(c => ifInit(c)(_.isNestedClass.get)), info.get.nestedClasses) } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 9b4451d492..8ded58d3d9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -216,7 +216,18 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { } private def setClassInfo(classSym: Symbol, classBType: ClassBType): ClassBType = { - val superClassSym = if (classSym.isImplClass) ObjectClass else classSym.superClass + // Check for isImplClass: trait implementation classes have NoSymbol as superClass + // Check for hasAnnotationFlag for SI-9393: the classfile / java source parsers add + // scala.annotation.Annotation as superclass to java annotations. In reality, java + // annotation classfiles have superclass Object (like any interface classfile). + val superClassSym = if (classSym.isImplClass || classSym.hasJavaAnnotationFlag) ObjectClass else { + val sc = classSym.superClass + // SI-9393: Java annotation classes don't have the ABSTRACT/INTERFACE flag, so they appear + // (wrongly) as superclasses. Fix this for BTypes: the java annotation will appear as interface + // (handled by method implementedInterfaces), the superclass is set to Object. + if (sc.hasJavaAnnotationFlag) ObjectClass + else sc + } assert( if (classSym == ObjectClass) superClassSym == NoSymbol diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 03f0236734..67921303b9 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -751,7 +751,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val (statics, body) = typeBody(AT, name) val templ = makeTemplate(annotationParents, body) addCompanionObject(statics, atPos(pos) { - ClassDef(mods, name, List(), templ) + ClassDef(mods | Flags.JAVA_ANNOTATION, name, List(), templ) }) } diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index 53241fb15b..d04bd3d3c8 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -345,6 +345,7 @@ object ClassfileConstants { case JAVA_ACC_ABSTRACT => if (isAnnotation) 0L else if (isClass) ABSTRACT else DEFERRED case JAVA_ACC_INTERFACE => if (isAnnotation) 0L else TRAIT | INTERFACE | ABSTRACT case JAVA_ACC_ENUM => ENUM + case JAVA_ACC_ANNOTATION => JAVA_ANNOTATION case _ => 0L } private def translateFlags(jflags: Int, baseFlags: Long, isClass: Boolean): Long = { @@ -360,6 +361,7 @@ object ClassfileConstants { res |= translateFlag0(jflags & JAVA_ACC_ABSTRACT) res |= translateFlag0(jflags & JAVA_ACC_INTERFACE) res |= translateFlag0(jflags & JAVA_ACC_ENUM) + res |= translateFlag0(jflags & JAVA_ACC_ANNOTATION) res } diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 1707061817..ab56020713 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -64,7 +64,7 @@ import scala.collection.{ mutable, immutable } // 46: ARTIFACT // 47: DEFAULTMETHOD/M // 48: ENUM -// 49: +// 49: JAVA_ANNOTATION // 50: // 51: lateDEFERRED // 52: lateFINAL @@ -120,7 +120,8 @@ class ModifierFlags { final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode // to see which symbols are marked as ARTIFACT, see scaladocs for FlagValues.ARTIFACT final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method - final val ENUM = 1L << 48 // symbol is an enum + final val ENUM = 1L << 48 // symbol is a java enum + final val JAVA_ANNOTATION = 1L << 49 // symbol is a java annotation // Overridden. def flagToString(flag: Long): String = "" @@ -172,12 +173,28 @@ class Flags extends ModifierFlags { final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED // ------- shift definitions ------------------------------------------------------- + // + // Flags from 1L to (1L << 50) are normal flags. + // + // The flags DEFERRED (1L << 4) to MODULE (1L << 8) have a `late` counterpart. Late flags change + // their counterpart from 0 to 1 after a specific phase (see below). The first late flag + // (lateDEFERRED) is at (1L << 51), i.e., late flags are shifted by 47. The last one is (1L << 55). + // + // The flags PROTECTED (1L) to PRIVATE (1L << 2) have a `not` counterpart. Negated flags change + // their counterpart from 1 to 0 after a specific phase (see below). They are shifted by 56, i.e., + // the first negated flag (notPROTECTED) is at (1L << 56), the last at (1L << 58). + // + // Late and negative flags are only enabled after certain phases, implemented by the phaseNewFlags + // method of the SubComponent, so they implement a bit of a flag history. + // + // The flags (1L << 59) to (1L << 63) are currently unused. If added to the InitialFlags mask, + // they could be used as normal flags. - final val InitialFlags = 0x0001FFFFFFFFFFFFL // flags that are enabled from phase 1. - final val LateFlags = 0x00FE000000000000L // flags that override flags in 0x1FC. - final val AntiFlags = 0x7F00000000000000L // flags that cancel flags in 0x07F - final val LateShift = 47L - final val AntiShift = 56L + final val InitialFlags = 0x0007FFFFFFFFFFFFL // normal flags, enabled from the first phase: 1L to (1L << 50) + final val LateFlags = 0x00F8000000000000L // flags that override flags in (1L << 4) to (1L << 8): DEFERRED, FINAL, INTERFACE, METHOD, MODULE + final val AntiFlags = 0x0700000000000000L // flags that cancel flags in 1L to (1L << 2): PROTECTED, OVERRIDE, PRIVATE + final val LateShift = 47 + final val AntiShift = 56 // Flags which sketchily share the same slot // 16: BYNAMEPARAM/M CAPTURED COVARIANT/M @@ -436,7 +453,7 @@ class Flags extends ModifierFlags { case ARTIFACT => "" // (1L << 46) case DEFAULTMETHOD => "" // (1L << 47) case ENUM => "" // (1L << 48) - case 0x2000000000000L => "" // (1L << 49) + case JAVA_ANNOTATION => "" // (1L << 49) case 0x4000000000000L => "" // (1L << 50) case `lateDEFERRED` => "" // (1L << 51) case `lateFINAL` => "" // (1L << 52) diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index aa8f4c532e..17f28ab1ca 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -83,6 +83,7 @@ trait HasFlags { def hasAccessorFlag = hasFlag(ACCESSOR) def hasDefault = hasFlag(DEFAULTPARAM) && hasFlag(METHOD | PARAM) // Second condition disambiguates with TRAIT def hasEnumFlag = hasFlag(ENUM) + def hasJavaAnnotationFlag = hasFlag(JAVA_ANNOTATION) @deprecated("Use isLocalToThis instead", "2.11.0") def hasLocalFlag = hasFlag(LOCAL) def isLocalToThis = hasFlag(LOCAL) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 478b1b9732..a3c3023500 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -732,7 +732,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def flags: Long = { if (Statistics.hotEnabled) Statistics.incCounter(flagsCount) val fs = _rawflags & phase.flagMask - (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift) + (fs | ((fs & LateFlags) >>> LateShift)) & ~((fs & AntiFlags) >>> AntiShift) } def flags_=(fs: Long) = _rawflags = fs def rawflags_=(x: Long) { _rawflags = x } diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala index ca50beae7f..702e5e279a 100644 --- a/test/files/jvm/innerClassAttribute/Test.scala +++ b/test/files/jvm/innerClassAttribute/Test.scala @@ -145,9 +145,7 @@ object Test extends BytecodeTest { def testA11() = { val List(ann) = innerClassNodes("A11") - // in the java class file, the INNERCLASS attribute has more flags (public | static | abstract | interface | annotation) - // the scala compiler has its own interpretation of java annotations ant their flags.. it only emits publicStatic. - assertMember(ann, "JavaAnnot_1", "Ann", flags = publicStatic) + assertMember(ann, "JavaAnnot_1", "Ann", flags = publicAbstractInterface | Flags.ACC_STATIC | Flags.ACC_ANNOTATION) } def testA13() = { diff --git a/test/files/pos/t9393/Named.java b/test/files/pos/t9393/Named.java deleted file mode 100644 index 144ddbf26e..0000000000 --- a/test/files/pos/t9393/Named.java +++ /dev/null @@ -1,3 +0,0 @@ -package bug; - -public @interface Named {} diff --git a/test/files/pos/t9393/NamedImpl.java b/test/files/pos/t9393/NamedImpl.java deleted file mode 100644 index 7918739c2b..0000000000 --- a/test/files/pos/t9393/NamedImpl.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2009-2015 Typesafe Inc. - */ -package bug; - -import bug.Named; -import java.io.Serializable; -import java.lang.annotation.Annotation; - -public class NamedImpl implements Named { - - public Class annotationType() { - return null; - } -} diff --git a/test/files/pos/t9393/NamedImpl_1.java b/test/files/pos/t9393/NamedImpl_1.java new file mode 100644 index 0000000000..02ec9b4671 --- /dev/null +++ b/test/files/pos/t9393/NamedImpl_1.java @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2009-2015 Typesafe Inc. + */ +package bug; + +import bug.Named_1; +import java.io.Serializable; +import java.lang.annotation.Annotation; + +public class NamedImpl_1 implements Named_1 { + + public Class annotationType() { + return null; + } +} diff --git a/test/files/pos/t9393/NamedImpl_2.java b/test/files/pos/t9393/NamedImpl_2.java new file mode 100644 index 0000000000..c87e94016d --- /dev/null +++ b/test/files/pos/t9393/NamedImpl_2.java @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2009-2015 Typesafe Inc. + */ +package bug; + +import bug.Named_2; +import java.io.Serializable; +import java.lang.annotation.Annotation; + +public class NamedImpl_2 implements Named_2 { + + public Class annotationType() { + return null; + } +} diff --git a/test/files/pos/t9393/Named_1.java b/test/files/pos/t9393/Named_1.java new file mode 100644 index 0000000000..30a6c9839a --- /dev/null +++ b/test/files/pos/t9393/Named_1.java @@ -0,0 +1,3 @@ +package bug; + +public @interface Named_1 {} diff --git a/test/files/pos/t9393/Named_2.java b/test/files/pos/t9393/Named_2.java new file mode 100644 index 0000000000..3210fb636a --- /dev/null +++ b/test/files/pos/t9393/Named_2.java @@ -0,0 +1,3 @@ +package bug; + +public @interface Named_2 {} diff --git a/test/files/pos/t9393/test.scala b/test/files/pos/t9393/test.scala deleted file mode 100644 index 4df0476c98..0000000000 --- a/test/files/pos/t9393/test.scala +++ /dev/null @@ -1,3 +0,0 @@ -class C { - new bug.NamedImpl -} diff --git a/test/files/pos/t9393/test_2.scala b/test/files/pos/t9393/test_2.scala new file mode 100644 index 0000000000..8ea346129d --- /dev/null +++ b/test/files/pos/t9393/test_2.scala @@ -0,0 +1,4 @@ +class C { + new bug.NamedImpl_1 // separate compilation, testing the classfile parser + new bug.NamedImpl_2 // mixed compilation, testing the java source parser +} diff --git a/test/junit/scala/tools/nsc/symtab/FlagsTest.scala b/test/junit/scala/tools/nsc/symtab/FlagsTest.scala new file mode 100644 index 0000000000..fc0e8b0f6b --- /dev/null +++ b/test/junit/scala/tools/nsc/symtab/FlagsTest.scala @@ -0,0 +1,89 @@ +package scala.tools.nsc +package symtab + +import org.junit.Assert._ +import scala.tools.testing.AssertUtil._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class FlagsTest { + object symbolTable extends SymbolTableForUnitTesting + import symbolTable._ + import Flags._ + + def sym = NoSymbol.newTermSymbol(nme.EMPTY) + + def withFlagMask[A](mask: Long)(body: => A): A = enteringPhase(new Phase(NoPhase) { + override def flagMask = mask + def name = "" + def run() = () + })(body) + + def testTimedFlag(flag: Long, test: Symbol => Boolean, enabling: Boolean) = { + assertEquals(withFlagMask(InitialFlags)(test(sym.setFlag(flag))), !enabling) + assertEquals(withFlagMask(InitialFlags | flag)(test(sym.setFlag(flag))), enabling) + } + + def testLate(flag: Long, test: Symbol => Boolean) = testTimedFlag(flag, test, enabling = true) + def testNot(flag: Long, test: Symbol => Boolean) = testTimedFlag(flag, test, enabling = false) + + @Test + def testTimedFlags(): Unit = { + testLate(lateDEFERRED, _.isDeferred) + testLate(lateFINAL, _.isFinal) + testLate(lateINTERFACE, _.isInterface) + testLate(lateMETHOD, _.isMethod) + testLate(lateMODULE, _.isModule) + testNot(PROTECTED | notPROTECTED, _.isProtected) + testNot(OVERRIDE | notOVERRIDE, _.isOverride) + testNot(PRIVATE | notPRIVATE, _.isPrivate) + + assertFalse(withFlagMask(AllFlags)(sym.setFlag(PRIVATE | notPRIVATE).isPrivate)) + + assertEquals(withFlagMask(InitialFlags)(sym.setFlag(PRIVATE | notPRIVATE).flags & PRIVATE), PRIVATE) + assertEquals(withFlagMask(AllFlags)(sym.setFlag(PRIVATE | notPRIVATE).flags & PRIVATE), 0) + } + + @Test + def normalLateOverlap(): Unit = { + // late flags are shifted by LateShift == 47. + // however, the first late flag is lateDEFERRED, which is DEFERRED << 47 == (1 << 4) << 47 == 1 << 51 + // the flags from 1 << 47 to 1 << 50 are not late flags. this is ensured by the LateFlags mask. + + for (i <- 0 to 3) { + val f = 1L << i + assertEquals(withFlagMask(AllFlags)(sym.setFlag(f << LateShift).flags & f), 0) // not treated as late flag + } + for (i <- 4 to 8) { + val f = 1L << i + assertEquals(withFlagMask(AllFlags)(sym.setFlag(f << LateShift).flags & f), f) // treated as late flag + } + } + + @Test + def normalAnti(): Unit = { + for (i <- 0 to 2) { + val f = 1L << i + assertEquals(withFlagMask(AllFlags)(sym.setFlag(f | (f << AntiShift)).flags & f), 0) // negated flags + } + for (i <- 3 to 7) { + val f = 1L << i + assertEquals(withFlagMask(AllFlags)(sym.setFlag(f | (f << AntiShift)).flags & f), f) // not negated + } + } + + @Test + def lateAntiCrossCheck(): Unit = { + val allButNegatable = AllFlags & ~(PROTECTED | OVERRIDE | PRIVATE) + val lateable = 0L | DEFERRED | FINAL | INTERFACE | METHOD | MODULE + val lateFlags = lateable << LateShift + val allButLateable = AllFlags & ~lateable + + assertEquals(withFlagMask(AllFlags)(sym.setFlag(AllFlags).flags), allButNegatable) + assertEquals(withFlagMask(AllFlags)(sym.setFlag(allButLateable).flags), allButNegatable) + + assertEquals(withFlagMask(AllFlags)(sym.setFlag(lateFlags).flags), lateFlags | lateable) + } +} -- cgit v1.2.3 From 76c133d48602ce1e7caee87940148cc37f1366b1 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 21 Jul 2015 22:13:25 +0200 Subject: Rename the ENUM / DEFAULTMETHOD flags to include JAVA_ Similar to the new JAVA_ANNOTATION flag, be more explicit about flags for java entities. --- .../tools/nsc/backend/jvm/BCodeAsmCommon.scala | 14 +-- .../tools/nsc/backend/jvm/BTypesFromSymbols.scala | 2 +- .../scala/tools/nsc/backend/jvm/GenASM.scala | 2 +- .../scala/tools/nsc/javac/JavaParsers.scala | 8 +- .../nsc/symtab/classfile/ClassfileParser.scala | 2 +- .../scala/tools/nsc/typechecker/Namers.scala | 4 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 4 +- .../reflect/internal/ClassfileConstants.scala | 2 +- .../scala/reflect/internal/Definitions.scala | 2 +- src/reflect/scala/reflect/internal/FlagSets.scala | 2 +- src/reflect/scala/reflect/internal/Flags.scala | 126 ++++++++++----------- src/reflect/scala/reflect/internal/HasFlags.scala | 82 +++++++------- 12 files changed, 125 insertions(+), 125 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala index f14ca0f40b..1cbf081b7c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala @@ -258,15 +258,15 @@ final class BCodeAsmCommon[G <: Global](val global: G) { GenBCode.mkFlags( // SI-9393: the classfile / java source parser make java annotation symbols look like classes. // here we recover the actual classfile flags. - if (classSym.hasJavaAnnotationFlag) ACC_ANNOTATION | ACC_INTERFACE | ACC_ABSTRACT else 0, - if (classSym.isPublic) ACC_PUBLIC else 0, - if (classSym.isFinal) ACC_FINAL else 0, + if (classSym.hasJavaAnnotationFlag) ACC_ANNOTATION | ACC_INTERFACE | ACC_ABSTRACT else 0, + if (classSym.isPublic) ACC_PUBLIC else 0, + if (classSym.isFinal) ACC_FINAL else 0, // see the link above. javac does the same: ACC_SUPER for all classes, but not interfaces. - if (classSym.isInterface) ACC_INTERFACE else ACC_SUPER, + if (classSym.isInterface) ACC_INTERFACE else ACC_SUPER, // for Java enums, we cannot trust `hasAbstractFlag` (see comment in enumFlags) - if (!classSym.hasEnumFlag && classSym.hasAbstractFlag) ACC_ABSTRACT else 0, - if (classSym.isArtifact) ACC_SYNTHETIC else 0, - if (classSym.hasEnumFlag) enumFlags else 0 + if (!classSym.hasJavaEnumFlag && classSym.hasAbstractFlag) ACC_ABSTRACT else 0, + if (classSym.isArtifact) ACC_SYNTHETIC else 0, + if (classSym.hasJavaEnumFlag) enumFlags else 0 ) } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 8ded58d3d9..45d9cc3ff3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -578,7 +578,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0, if (sym.isArtifact) ACC_SYNTHETIC else 0, if (sym.isClass && !sym.isInterface) ACC_SUPER else 0, - if (sym.hasEnumFlag) ACC_ENUM else 0, + if (sym.hasJavaEnumFlag) ACC_ENUM else 0, if (sym.isVarargsMethod) ACC_VARARGS else 0, if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0, if (sym.isDeprecated) asm.Opcodes.ACC_DEPRECATED else 0 diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index ccad50616c..8348306e03 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -307,7 +307,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0, if (sym.isArtifact) ACC_SYNTHETIC else 0, if (sym.isClass && !sym.isInterface) ACC_SUPER else 0, - if (sym.hasEnumFlag) ACC_ENUM else 0, + if (sym.hasJavaEnumFlag) ACC_ENUM else 0, if (sym.isVarargsMethod) ACC_VARARGS else 0, if (sym.hasFlag(Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0 ) diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 67921303b9..eb25eb6e06 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -370,7 +370,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { flags |= Flags.FINAL in.nextToken() case DEFAULT => - flags |= Flags.DEFAULTMETHOD + flags |= Flags.JAVA_DEFAULTMETHOD in.nextToken() case NATIVE => addAnnot(NativeAttr) @@ -489,7 +489,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val vparams = formalParams() if (!isVoid) rtpt = optArrayBrackets(rtpt) optThrows() - val isConcreteInterfaceMethod = !inInterface || (mods hasFlag Flags.DEFAULTMETHOD) || (mods hasFlag Flags.STATIC) + val isConcreteInterfaceMethod = !inInterface || (mods hasFlag Flags.JAVA_DEFAULTMETHOD) || (mods hasFlag Flags.STATIC) val bodyOk = !(mods1 hasFlag Flags.DEFERRED) && isConcreteInterfaceMethod val body = if (bodyOk && in.token == LBRACE) { @@ -809,7 +809,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { if (hasAbstractMember) Flags.ABSTRACT else 0l } addCompanionObject(consts ::: statics ::: predefs, atPos(pos) { - ClassDef(mods | Flags.ENUM | finalFlag | abstractFlag, name, List(), + ClassDef(mods | Flags.JAVA_ENUM | finalFlag | abstractFlag, name, List(), makeTemplate(superclazz :: interfaces, body)) }) } @@ -830,7 +830,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { skipAhead() accept(RBRACE) } - ValDef(Modifiers(Flags.ENUM | Flags.STABLE | Flags.JAVA | Flags.STATIC), name.toTermName, enumType, blankExpr) + ValDef(Modifiers(Flags.JAVA_ENUM | Flags.STABLE | Flags.JAVA | Flags.STATIC), name.toTermName, enumType, blankExpr) } (res, hasClassBody) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 91355693ee..06a0299d2a 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -862,7 +862,7 @@ abstract class ClassfileParser { srcfile0 = settings.outputDirs.srcFilesFor(in.file, srcpath).find(_.exists) case tpnme.CodeATTR => if (sym.owner.isInterface) { - sym setFlag DEFAULTMETHOD + sym setFlag JAVA_DEFAULTMETHOD log(s"$sym in ${sym.owner} is a java8+ default method.") } in.skip(attrLen) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index c1655467e9..4ad81b60ae 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -145,8 +145,8 @@ trait Namers extends MethodSynthesis { // while Scala's enum constants live directly in the class. // We don't check for clazz.superClass == JavaEnumClass, because this causes a illegal // cyclic reference error. See the commit message for details. - if (context.unit.isJava) owner.companionClass.hasEnumFlag else owner.hasEnumFlag - vd.mods.hasAllFlags(ENUM | STABLE | STATIC) && ownerHasEnumFlag + if (context.unit.isJava) owner.companionClass.hasJavaEnumFlag else owner.hasJavaEnumFlag + vd.mods.hasAllFlags(JAVA_ENUM | STABLE | STATIC) && ownerHasEnumFlag } def setPrivateWithin[T <: Symbol](tree: Tree, sym: T, mods: Modifiers): T = diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 4b30b4e436..d86a72c1a8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -421,7 +421,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans overrideError("cannot be used here - classes can only override abstract types") } else if (other.isEffectivelyFinal) { // (1.2) overrideError("cannot override final member") - } else if (!other.isDeferredOrDefault && !other.hasFlag(DEFAULTMETHOD) && !member.isAnyOverride && !member.isSynthetic) { // (*) + } else if (!other.isDeferredOrJavaDefault && !other.hasFlag(JAVA_DEFAULTMETHOD) && !member.isAnyOverride && !member.isSynthetic) { // (*) // (*) Synthetic exclusion for (at least) default getters, fixes SI-5178. We cannot assign the OVERRIDE flag to // the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket. if (isNeitherInClass && !(other.owner isSubClass member.owner)) @@ -604,7 +604,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def checkNoAbstractMembers(): Unit = { // Avoid spurious duplicates: first gather any missing members. def memberList = clazz.info.nonPrivateMembersAdmitting(VBRIDGE) - val (missing, rest) = memberList partition (m => m.isDeferredNotDefault && !ignoreDeferred(m)) + val (missing, rest) = memberList partition (m => m.isDeferredNotJavaDefault && !ignoreDeferred(m)) // Group missing members by the name of the underlying symbol, // to consolidate getters and setters. val grouped = missing groupBy (sym => analyzer.underlyingSymbol(sym).name) diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index d04bd3d3c8..e5d97e8959 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -344,7 +344,7 @@ object ClassfileConstants { case JAVA_ACC_STATIC => STATIC case JAVA_ACC_ABSTRACT => if (isAnnotation) 0L else if (isClass) ABSTRACT else DEFERRED case JAVA_ACC_INTERFACE => if (isAnnotation) 0L else TRAIT | INTERFACE | ABSTRACT - case JAVA_ACC_ENUM => ENUM + case JAVA_ACC_ENUM => JAVA_ENUM case JAVA_ACC_ANNOTATION => JAVA_ANNOTATION case _ => 0L } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 3552eb1713..02fa3c882b 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -815,7 +815,7 @@ trait Definitions extends api.StandardDefinitions { // must filter out "universal" members (getClass is deferred for some reason) val deferredMembers = ( tp membersBasedOnFlags (excludedFlags = BridgeAndPrivateFlags, requiredFlags = METHOD) - filter (mem => mem.isDeferredNotDefault && !isUniversalMember(mem)) // TODO: test + filter (mem => mem.isDeferredNotJavaDefault && !isUniversalMember(mem)) // TODO: test ) // if there is only one, it's monomorphic and has a single argument list diff --git a/src/reflect/scala/reflect/internal/FlagSets.scala b/src/reflect/scala/reflect/internal/FlagSets.scala index ef9c77878f..b6521634fb 100644 --- a/src/reflect/scala/reflect/internal/FlagSets.scala +++ b/src/reflect/scala/reflect/internal/FlagSets.scala @@ -42,7 +42,7 @@ trait FlagSets extends api.FlagSets { self: SymbolTable => val DEFAULTPARAM : FlagSet = Flags.DEFAULTPARAM val PRESUPER : FlagSet = Flags.PRESUPER val DEFAULTINIT : FlagSet = Flags.DEFAULTINIT - val ENUM : FlagSet = Flags.ENUM + val ENUM : FlagSet = Flags.JAVA_ENUM val PARAMACCESSOR : FlagSet = Flags.PARAMACCESSOR val CASEACCESSOR : FlagSet = Flags.CASEACCESSOR val SYNTHETIC : FlagSet = Flags.SYNTHETIC diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index ab56020713..754b96a9dd 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -15,65 +15,65 @@ import scala.collection.{ mutable, immutable } // // Generated by mkFlagsTable() at Thu Feb 02 20:31:52 PST 2012 // -// 0: PROTECTED/M -// 1: OVERRIDE/M -// 2: PRIVATE/M -// 3: ABSTRACT/M -// 4: DEFERRED/M -// 5: FINAL/M -// 6: METHOD -// 7: INTERFACE/M -// 8: MODULE -// 9: IMPLICIT/M -// 10: SEALED/M -// 11: CASE/M -// 12: MUTABLE/M -// 13: PARAM/M -// 14: PACKAGE -// 15: MACRO/M -// 16: BYNAMEPARAM/M CAPTURED COVARIANT/M -// 17: CONTRAVARIANT/M INCONSTRUCTOR LABEL -// 18: ABSOVERRIDE/M -// 19: LOCAL/M -// 20: JAVA/M -// 21: SYNTHETIC -// 22: STABLE -// 23: STATIC/M -// 24: CASEACCESSOR/M -// 25: DEFAULTPARAM/M TRAIT/M -// 26: BRIDGE -// 27: ACCESSOR -// 28: SUPERACCESSOR -// 29: PARAMACCESSOR/M -// 30: MODULEVAR -// 31: LAZY/M -// 32: IS_ERROR -// 33: OVERLOADED -// 34: LIFTED -// 35: EXISTENTIAL MIXEDIN -// 36: EXPANDEDNAME -// 37: IMPLCLASS PRESUPER/M -// 38: TRANS_FLAG -// 39: LOCKED -// 40: SPECIALIZED -// 41: DEFAULTINIT/M -// 42: VBRIDGE -// 43: VARARGS -// 44: TRIEDCOOKING -// 45: SYNCHRONIZED/M -// 46: ARTIFACT -// 47: DEFAULTMETHOD/M -// 48: ENUM +// 0: PROTECTED/M +// 1: OVERRIDE/M +// 2: PRIVATE/M +// 3: ABSTRACT/M +// 4: DEFERRED/M +// 5: FINAL/M +// 6: METHOD +// 7: INTERFACE/M +// 8: MODULE +// 9: IMPLICIT/M +// 10: SEALED/M +// 11: CASE/M +// 12: MUTABLE/M +// 13: PARAM/M +// 14: PACKAGE +// 15: MACRO/M +// 16: BYNAMEPARAM/M CAPTURED COVARIANT/M +// 17: CONTRAVARIANT/M INCONSTRUCTOR LABEL +// 18: ABSOVERRIDE/M +// 19: LOCAL/M +// 20: JAVA/M +// 21: SYNTHETIC +// 22: STABLE +// 23: STATIC/M +// 24: CASEACCESSOR/M +// 25: DEFAULTPARAM/M TRAIT/M +// 26: BRIDGE +// 27: ACCESSOR +// 28: SUPERACCESSOR +// 29: PARAMACCESSOR/M +// 30: MODULEVAR +// 31: LAZY/M +// 32: IS_ERROR +// 33: OVERLOADED +// 34: LIFTED +// 35: EXISTENTIAL MIXEDIN +// 36: EXPANDEDNAME +// 37: IMPLCLASS PRESUPER/M +// 38: TRANS_FLAG +// 39: LOCKED +// 40: SPECIALIZED +// 41: DEFAULTINIT/M +// 42: VBRIDGE +// 43: VARARGS +// 44: TRIEDCOOKING +// 45: SYNCHRONIZED/M +// 46: ARTIFACT +// 47: JAVA_DEFAULTMETHOD/M +// 48: JAVA_ENUM // 49: JAVA_ANNOTATION // 50: -// 51: lateDEFERRED -// 52: lateFINAL -// 53: lateMETHOD -// 54: lateINTERFACE -// 55: lateMODULE -// 56: notPROTECTED -// 57: notOVERRIDE -// 58: notPRIVATE +// 51: lateDEFERRED +// 52: lateFINAL +// 53: lateMETHOD +// 54: lateINTERFACE +// 55: lateMODULE +// 56: notPROTECTED +// 57: notOVERRIDE +// 58: notPRIVATE // 59: // 60: // 61: @@ -119,9 +119,9 @@ class ModifierFlags { final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode // to see which symbols are marked as ARTIFACT, see scaladocs for FlagValues.ARTIFACT - final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method - final val ENUM = 1L << 48 // symbol is a java enum - final val JAVA_ANNOTATION = 1L << 49 // symbol is a java annotation + final val JAVA_DEFAULTMETHOD = 1L << 47 // symbol is a java default method + final val JAVA_ENUM = 1L << 48 // symbol is a java enum + final val JAVA_ANNOTATION = 1L << 49 // symbol is a java annotation // Overridden. def flagToString(flag: Long): String = "" @@ -260,7 +260,7 @@ class Flags extends ModifierFlags { */ final val ExplicitFlags = PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED | - OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY | DEFAULTMETHOD + OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY | JAVA_DEFAULTMETHOD /** The two bridge flags */ final val BridgeFlags = BRIDGE | VBRIDGE @@ -451,8 +451,8 @@ class Flags extends ModifierFlags { case TRIEDCOOKING => "" // (1L << 44) case SYNCHRONIZED => "" // (1L << 45) case ARTIFACT => "" // (1L << 46) - case DEFAULTMETHOD => "" // (1L << 47) - case ENUM => "" // (1L << 48) + case JAVA_DEFAULTMETHOD => "" // (1L << 47) + case JAVA_ENUM => "" // (1L << 48) case JAVA_ANNOTATION => "" // (1L << 49) case 0x4000000000000L => "" // (1L << 50) case `lateDEFERRED` => "" // (1L << 51) diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index 17f28ab1ca..5162b15206 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -79,50 +79,50 @@ trait HasFlags { // Tests which come through cleanly: both Symbol and Modifiers use these // identically, testing for a single flag. - def hasAbstractFlag = hasFlag(ABSTRACT) - def hasAccessorFlag = hasFlag(ACCESSOR) - def hasDefault = hasFlag(DEFAULTPARAM) && hasFlag(METHOD | PARAM) // Second condition disambiguates with TRAIT - def hasEnumFlag = hasFlag(ENUM) + def hasAbstractFlag = hasFlag(ABSTRACT) + def hasAccessorFlag = hasFlag(ACCESSOR) + def hasDefault = hasFlag(DEFAULTPARAM) && hasFlag(METHOD | PARAM) // Second condition disambiguates with TRAIT + def hasJavaEnumFlag = hasFlag(JAVA_ENUM) def hasJavaAnnotationFlag = hasFlag(JAVA_ANNOTATION) @deprecated("Use isLocalToThis instead", "2.11.0") - def hasLocalFlag = hasFlag(LOCAL) - def isLocalToThis = hasFlag(LOCAL) - def hasModuleFlag = hasFlag(MODULE) - def hasPackageFlag = hasFlag(PACKAGE) - def hasStableFlag = hasFlag(STABLE) - def hasStaticFlag = hasFlag(STATIC) - def isAbstractOverride = hasFlag(ABSOVERRIDE) - def isAnyOverride = hasFlag(OVERRIDE | ABSOVERRIDE) - def isCase = hasFlag(CASE) - def isCaseAccessor = hasFlag(CASEACCESSOR) - def isDeferred = hasFlag(DEFERRED) - def isFinal = hasFlag(FINAL) - def isArtifact = hasFlag(ARTIFACT) - def isImplicit = hasFlag(IMPLICIT) - def isInterface = hasFlag(INTERFACE) - def isJavaDefined = hasFlag(JAVA) - def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag - def isLazy = hasFlag(LAZY) - def isLifted = hasFlag(LIFTED) - def isMacro = hasFlag(MACRO) - def isMutable = hasFlag(MUTABLE) - def isOverride = hasFlag(OVERRIDE) - def isParamAccessor = hasFlag(PARAMACCESSOR) - def isPrivate = hasFlag(PRIVATE) + def hasLocalFlag = hasFlag(LOCAL) + def isLocalToThis = hasFlag(LOCAL) + def hasModuleFlag = hasFlag(MODULE) + def hasPackageFlag = hasFlag(PACKAGE) + def hasStableFlag = hasFlag(STABLE) + def hasStaticFlag = hasFlag(STATIC) + def isAbstractOverride = hasFlag(ABSOVERRIDE) + def isAnyOverride = hasFlag(OVERRIDE | ABSOVERRIDE) + def isCase = hasFlag(CASE) + def isCaseAccessor = hasFlag(CASEACCESSOR) + def isDeferred = hasFlag(DEFERRED) + def isFinal = hasFlag(FINAL) + def isArtifact = hasFlag(ARTIFACT) + def isImplicit = hasFlag(IMPLICIT) + def isInterface = hasFlag(INTERFACE) + def isJavaDefined = hasFlag(JAVA) + def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag + def isLazy = hasFlag(LAZY) + def isLifted = hasFlag(LIFTED) + def isMacro = hasFlag(MACRO) + def isMutable = hasFlag(MUTABLE) + def isOverride = hasFlag(OVERRIDE) + def isParamAccessor = hasFlag(PARAMACCESSOR) + def isPrivate = hasFlag(PRIVATE) @deprecated ("Use `hasPackageFlag` instead", "2.11.0") - def isPackage = hasFlag(PACKAGE) - def isPrivateLocal = hasAllFlags(PrivateLocal) - def isProtected = hasFlag(PROTECTED) - def isProtectedLocal = hasAllFlags(ProtectedLocal) - def isPublic = hasNoFlags(PRIVATE | PROTECTED) && !hasAccessBoundary - def isSealed = hasFlag(SEALED) - def isSpecialized = hasFlag(SPECIALIZED) - def isSuperAccessor = hasFlag(SUPERACCESSOR) - def isSynthetic = hasFlag(SYNTHETIC) - def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM) - - def isDeferredOrDefault = hasFlag(DEFERRED | DEFAULTMETHOD) - def isDeferredNotDefault = isDeferred && !hasFlag(DEFAULTMETHOD) + def isPackage = hasFlag(PACKAGE) + def isPrivateLocal = hasAllFlags(PrivateLocal) + def isProtected = hasFlag(PROTECTED) + def isProtectedLocal = hasAllFlags(ProtectedLocal) + def isPublic = hasNoFlags(PRIVATE | PROTECTED) && !hasAccessBoundary + def isSealed = hasFlag(SEALED) + def isSpecialized = hasFlag(SPECIALIZED) + def isSuperAccessor = hasFlag(SUPERACCESSOR) + def isSynthetic = hasFlag(SYNTHETIC) + def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM) + + def isDeferredOrJavaDefault = hasFlag(DEFERRED | JAVA_DEFAULTMETHOD) + def isDeferredNotJavaDefault = isDeferred && !hasFlag(JAVA_DEFAULTMETHOD) def flagBitsToString(bits: Long): String = { // Fast path for common case -- cgit v1.2.3 From 59f1ee5989c43206676d831ff696b5d656ac6727 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 21 Jul 2015 22:03:00 +0200 Subject: Query methods in api.Symbols for Java flags Adds query methods to the public reflection API for querying the JAVA_ENUM and JAVA_ANNOTATION flags. Didn't include JAVA_DEFAULTMETHOD because it does not correspond to a real java classfile flag (just a non-abstract method in an interface), and we want to clean the usage of this flag before adding it to a public API. The flags themselfs are not added to the reflection API. A comment in api/FlagSets.scala says: Q: I have a pretty flag. Can I put it here? A: Only if there's a tree that cannot be built without it. If you want to put a flag here so that it can be tested against, introduce an `isXXX` method in one of the api.Symbols classes instead. --- src/reflect/scala/reflect/api/FlagSets.scala | 1 + src/reflect/scala/reflect/api/Symbols.scala | 12 ++++++++++++ src/reflect/scala/reflect/internal/Symbols.scala | 3 +++ test/junit/scala/tools/nsc/symtab/FlagsTest.scala | 7 +++++++ 4 files changed, 23 insertions(+) diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index d3294dad9b..2d5d1d5d6b 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -173,6 +173,7 @@ trait FlagSets { self: Universe => * - the enum's class * - enum constants **/ + @deprecated("Use `isJavaEnum` on the corresponding symbol instead.", since = "2.11.8") val ENUM: FlagSet /** Flag indicating that tree represents a parameter of the primary constructor of some class diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index b7234ba47a..9e9fe5d67b 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -504,6 +504,18 @@ trait Symbols { self: Universe => */ def isImplicit: Boolean + /** Does this symbol represent a java enum class or a java enum value? + * + * @group Tests + */ + def isJavaEnum: Boolean + + /** Does this symbol represent a java annotation interface? + * + * @group Tests + */ + def isJavaAnnotation: Boolean + /******************* helpers *******************/ /** Provides an alternate if symbol is a NoSymbol. diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index a3c3023500..ca83f5ef85 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -102,6 +102,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isPrivateThis = (this hasFlag PRIVATE) && (this hasFlag LOCAL) def isProtectedThis = (this hasFlag PROTECTED) && (this hasFlag LOCAL) + def isJavaEnum: Boolean = hasJavaEnumFlag + def isJavaAnnotation: Boolean = hasJavaAnnotationFlag + def newNestedSymbol(name: Name, pos: Position, newFlags: Long, isClass: Boolean): Symbol = name match { case n: TermName => newTermSymbol(n, pos, newFlags) case n: TypeName => if (isClass) newClassSymbol(n, pos, newFlags) else newNonClassSymbol(n, pos, newFlags) diff --git a/test/junit/scala/tools/nsc/symtab/FlagsTest.scala b/test/junit/scala/tools/nsc/symtab/FlagsTest.scala index fc0e8b0f6b..08a37fcb3c 100644 --- a/test/junit/scala/tools/nsc/symtab/FlagsTest.scala +++ b/test/junit/scala/tools/nsc/symtab/FlagsTest.scala @@ -86,4 +86,11 @@ class FlagsTest { assertEquals(withFlagMask(AllFlags)(sym.setFlag(lateFlags).flags), lateFlags | lateable) } + + @Test + def javaClassMirrorAnnotationFlag(): Unit = { + import scala.reflect.runtime.universe._ + val dep = typeOf[java.lang.Deprecated].typeSymbol + assertTrue(dep.isJavaAnnotation && dep.isJava) + } } -- cgit v1.2.3