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
|
/* NSC -- new Scala compiler
* Copyright 2007-2011 LAMP/EPFL
* @author Martin Odersky
*/
package scala.reflect
package internal
import util._
/** AnnotationInfo and its helpers */
trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
/** Arguments to classfile annotations (which are written to
* bytecode as java annotations) are either:
* <ul>
* <li>constants</li>
* <li>arrays of constants</li>
* <li>or nested classfile annotations</li>
* </ul>
*/
abstract class ClassfileAnnotArg
/** Represents a compile-time Constant (Boolean, Byte, Short,
* Char, Int, Long, Float, Double, String, java.lang.Class or
* an instance of a Java enumeration value).
*/
case class LiteralAnnotArg(const: Constant)
extends ClassfileAnnotArg {
override def toString = const.escapedStringValue
}
object LiteralAnnotArg extends LiteralAnnotArgExtractor
/** Represents an array of classfile annotation arguments */
case class ArrayAnnotArg(args: Array[ClassfileAnnotArg])
extends ClassfileAnnotArg {
override def toString = args.mkString("[", ", ", "]")
}
object ArrayAnnotArg extends ArrayAnnotArgExtractor
/** A specific annotation argument that encodes an array of bytes as an array of `Long`. The type of the argument
* declared in the annotation must be `String`. This specialised class is used to encode scala signatures for
* reasons of efficiency, both in term of class-file size and in term of compiler performance. */
case class ScalaSigBytes(bytes: Array[Byte]) extends ClassfileAnnotArg {
override def toString = (bytes map { byte => (byte & 0xff).toHexString }).mkString("[ ", " ", " ]")
lazy val encodedBytes = ByteCodecs.encode(bytes)
def isLong: Boolean = (encodedBytes.length > 65535)
def sigAnnot: Type =
if (this.isLong)
definitions.ScalaLongSignatureAnnotation.tpe
else
definitions.ScalaSignatureAnnotation.tpe
}
/** Represents a nested classfile annotation */
case class NestedAnnotArg(annInfo: AnnotationInfo)
extends ClassfileAnnotArg {
// The nested annotation should not have any Scala annotation arguments
assert(annInfo.args.isEmpty, annInfo.args)
override def toString = annInfo.toString
}
object NestedAnnotArg extends NestedAnnotArgExtractor
class AnnotationInfoBase
/** <p>
* Typed information about an annotation. It can be attached to
* either a symbol or an annotated type.
* </p>
* <p>
* Annotations are written to the classfile as java annotations
* if <code>atp</code> conforms to <code>ClassfileAnnotation</code>
* (the classfile parser adds this interface to any Java annotation
* class).
* </p>
* <p>
* Annotations are pickled (written to scala symtab attribute
* in the classfile) if <code>atp</code> inherits form
* <code>StaticAnnotation</code>.
* </p>
* <p>
* <code>args</code> stores arguments to Scala annotations,
* represented as typed trees. Note that these trees are not
* transformed by any phases following the type-checker.
* </p>
* <p>
* <code>assocs</code> stores arguments to classfile annotations
* as name-value pairs.
* </p>
*/
case class AnnotationInfo(atp: Type, args: List[Tree],
assocs: List[(Name, ClassfileAnnotArg)])
extends AnnotationInfoBase {
// Classfile annot: args empty. Scala annot: assocs empty.
assert(args.isEmpty || assocs.isEmpty)
private var rawpos: Position = NoPosition
def pos = rawpos
def setPos(pos: Position): this.type = {
rawpos = pos
this
}
lazy val isTrivial: Boolean = atp.isTrivial && !(args exists (_.exists(_.isInstanceOf[This]))) // see annotationArgRewriter
override def toString: String = atp +
(if (!args.isEmpty) args.mkString("(", ", ", ")") else "") +
(if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "")
/** Check whether the type or any of the arguments are erroneous */
def isErroneous = atp.isErroneous || args.exists(_.isErroneous)
/** Check whether any of the arguments mention a symbol */
def refsSymbol(sym: Symbol) =
args.exists(_.exists(_.symbol == sym))
/** Change all ident's with Symbol "from" to instead use symbol "to" */
def substIdentSyms(from: Symbol, to: Symbol) = {
val subs = new TreeSymSubstituter(List(from), List(to))
AnnotationInfo(atp, args.map(subs(_)), assocs).setPos(pos)
}
// !!! when annotation arguments are not literal strings, but any sort of
// assembly of strings, there is a fair chance they will turn up here not as
// Literal(const) but some arbitrary AST.
def stringArg(index: Int): Option[String] = if(args.size > index) Some(args(index) match {
case Literal(const) => const.stringValue
case x => x.toString // should not be necessary, but better than silently ignoring an issue
}) else None
def intArg(index: Int): Option[Int] = if(args.size > index) Some(args(index)) collect {
case Literal(Constant(x: Int)) => x
} else None
}
object AnnotationInfo extends AnnotationInfoExtractor
lazy val classfileAnnotArgManifest: ClassManifest[ClassfileAnnotArg] =
reflect.ClassManifest.classType(classOf[ClassfileAnnotArg])
/** Symbol annotations parsed in Namer (typeCompleter of
* definitions) have to be lazy (#1782)
*/
case class LazyAnnotationInfo(annot: () => AnnotationInfo)
extends AnnotationInfoBase
}
|