summaryrefslogtreecommitdiff
path: root/src/compiler/scala/reflect/internal/HasFlags.scala
blob: 348f81c51d83d40d18d65674fde9d2154fa6a76b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package scala.reflect
package internal

import Flags._

/** Common code utilized by Modifiers (which carry the flags associated
 *  with Trees) and Symbol.
 */
trait HasFlags {
  type AccessBoundaryType
  type AnnotationType

  /** Though both Symbol and Modifiers widen this method to public, it's
   *  defined protected here to give us the option in the future to route
   *  flag methods through accessors and disallow raw flag manipulation.
   *  And after that, perhaps, on some magical day: a typesafe enumeration.
   */
  protected def flags: Long

  /** Access level encoding: there are three scala flags (PRIVATE, PROTECTED,
   *  and LOCAL) which combine with value privateWithin (the "foo" in private[foo])
   *  to define from where an entity can be accessed.  The meanings are as follows:
   *
   *  PRIVATE     access restricted to class only.
   *  PROTECTED   access restricted to class and subclasses only.
   *  LOCAL       can only be set in conjunction with PRIVATE or PROTECTED.
   *              Further restricts access to the same object instance.
   *
   *  In addition, privateWithin can be used to set a visibility barrier.
   *  When set, everything contained in the named enclosing package or class
   *  has access.  It is incompatible with PRIVATE or LOCAL, but is additive
   *  with PROTECTED (i.e. if either the flags or privateWithin allow access,
   *  then it is allowed.)
   *
   *  The java access levels translate as follows:
   *
   *  java private:     hasFlag(PRIVATE)                && !hasAccessBoundary
   *  java package:     !hasFlag(PRIVATE | PROTECTED)   && (privateWithin == enclosing package)
   *  java protected:   hasFlag(PROTECTED)              && (privateWithin == enclosing package)
   *  java public:      !hasFlag(PRIVATE | PROTECTED)   && !hasAccessBoundary
   */
  def privateWithin: AccessBoundaryType

  /** A list of annotations attached to this entity.
   */
  def annotations: List[AnnotationType]

  /** Whether this entity has a "privateWithin" visibility barrier attached.
   */
  def hasAccessBoundary: Boolean

  /** Whether this entity has ANY of the flags in the given mask.
   */
  def hasFlag(flag: Long): Boolean

  /** Whether this entity has ALL of the flags in the given mask.
   */
  def hasAllFlags(mask: Long): Boolean

  /** Whether this entity has NONE of the flags in the given mask.
   */
  def hasNoFlags(mask: Long): Boolean = !hasFlag(mask)

  /** The printable representation of this entity's flags and access boundary,
   *  restricted to flags in the given mask.
   */
  def flagString: String = flagString(flagMask)
  def flagString(mask: Long): String = calculateFlagString(flags & mask)
  
  /** The default mask determining which flags to display.
   */
  def flagMask: Long = AllFlags

  /** The string representation of a single bit, seen from this
   *  flag carrying entity.
   */
  def resolveOverloadedFlag(flag: Long): String = Flags.flagToString(flag)
  
  def privateWithinString = if (hasAccessBoundary) privateWithin.toString else ""

  protected def isSetting(f: Long, mask: Long)  = !hasFlag(f) && ((mask & f) != 0L)
  protected def isClearing(f: Long, mask: Long) =  hasFlag(f) && ((mask & f) != 0L)

  // Tests which come through cleanly: both Symbol and Modifiers use these
  // identically, testing for a single flag.
  def isCase      = hasFlag(CASE     )
  def isFinal     = hasFlag(FINAL    )
  def isImplicit  = hasFlag(IMPLICIT )
  def isLazy      = hasFlag(LAZY     )
  def isMutable   = hasFlag(MUTABLE  )  // in Modifiers, formerly isVariable
  def isOverride  = hasFlag(OVERRIDE )
  def isPrivate   = hasFlag(PRIVATE  )
  def isProtected = hasFlag(PROTECTED)
  def isSynthetic = hasFlag(SYNTHETIC)
  def isInterface = hasFlag(INTERFACE)

  // Newly introduced based on having a reasonably obvious clean translation.
  def isPrivateLocal   = hasAllFlags(PrivateLocal)
  def isProtectedLocal = hasAllFlags(ProtectedLocal)
  def isParamAccessor  = hasFlag(PARAMACCESSOR)
  def isCaseAccessor   = hasFlag(CASEACCESSOR)
  def isSuperAccessor  = hasFlag(SUPERACCESSOR)
  def isLifted         = hasFlag(LIFTED)

  // Formerly the Modifiers impl did not include the access boundary check,
  // which must have been a bug.
  def isPublic = hasNoFlags(PRIVATE | PROTECTED) && !hasAccessBoundary

  // Removed isClass qualification since the flag isn't overloaded and
  // sym.isClass is enforced in Namers#validate.
  def isSealed = hasFlag(SEALED)

  // Removed !isClass qualification since the flag isn't overloaded.
  def isDeferred = hasFlag(DEFERRED)

  // Dropped isTerm condition because flag isn't overloaded.
  def isAbstractOverride = hasFlag(ABSOVERRIDE)
  def isAnyOverride = hasFlag(OVERRIDE | ABSOVERRIDE)

  // Disambiguating: DEFAULTPARAM, TRAIT
  def hasDefault     = hasAllFlags(DEFAULTPARAM | PARAM)
  def isTrait        = hasFlag(TRAIT) && !hasFlag(PARAM)

  // Straightforwardly named accessors already being used differently.
  // These names are most likely temporary.
  def hasAbstractFlag      = hasFlag(ABSTRACT)
  def hasAccessorFlag      = hasFlag(ACCESSOR)
  def hasLocalFlag         = hasFlag(LOCAL)
  def hasModuleFlag        = hasFlag(MODULE)
  def hasPackageFlag       = hasFlag(PACKAGE)
  def hasStableFlag        = hasFlag(STABLE)
  def hasStaticFlag        = hasFlag(STATIC)

  // Disambiguating: LABEL, CONTRAVARIANT, INCONSTRUCTOR
  def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag
  // Cannot effectively disambiguate the others at this level.
  def hasContravariantFlag = hasFlag(CONTRAVARIANT)
  def hasInConstructorFlag = hasFlag(INCONSTRUCTOR)

  // Name
  def isJavaDefined = hasFlag(JAVA)

  def flagBitsToString(bits: Long): String = {
    // Fast path for common case
    if (bits == 0L) "" else {
      var sb: StringBuilder = null
      var i = 0
      while (i <= MaxBitPosition) {
        val flag = Flags.rawFlagPickledOrder(i)
        if ((bits & flag) != 0L) {
          val s = resolveOverloadedFlag(flag)
          if (s.length > 0) {
            if (sb eq null) sb = new StringBuilder append s
            else if (sb.length == 0) sb append s
            else sb append " " append s
          }
        }
        i += 1
      }
      if (sb eq null) "" else sb.toString
    }
  }

  def accessString: String = {
    val pw = privateWithinString
    
    if (pw == "") {
      if (hasAllFlags(PrivateLocal)) "private[this]"
      else if (hasAllFlags(ProtectedLocal)) "protected[this]"
      else if (hasFlag(PRIVATE)) "private"
      else if (hasFlag(PROTECTED)) "protected"
      else ""
    }
    else if (hasFlag(PROTECTED)) "protected[" + pw + "]"
    else "private[" + pw + "]"
  }
  protected def calculateFlagString(basis: Long): String = {
    val access    = accessString
    val nonAccess = flagBitsToString(basis & ~AccessFlags)
    
    if (access == "") nonAccess
    else if (nonAccess == "") access
    else nonAccess + " " + access
  }

  // Backward compat section
  @deprecated( "Use isTrait", "2.10.0")
  def hasTraitFlag = hasFlag(TRAIT)
  @deprecated("Use hasDefault", "2.10.0")
  def hasDefaultFlag = hasFlag(DEFAULTPARAM)
  @deprecated("", "2.9.0")
  def isAbstract = hasFlag(ABSTRACT)
  @deprecated("Use isValueParameter or isTypeParameter", "2.10.0")
  def isParameter = hasFlag(PARAM)
  @deprecated("Use flagString", "2.10.0")
  def defaultFlagString = flagString
  @deprecated("Use flagString(mask)", "2.10.0")
  def hasFlagsToString(mask: Long): String = flagString(mask)
}