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
|
/* NSC -- new Scala compiler
* Copyright 2007-2009 LAMP/EPFL
* @author Martin Odersky
*/
// $Id$
package scala.tools.nsc.symtab
import scala.tools.nsc.transform.Reifiers
import util._
/** AnnotationInfo and its helpers */
trait AnnotationInfos {
self: SymbolTable =>
/** Convert a tree to a Constant, if possible */
private def tree2cons(tree: Tree): Option[Constant] =
tree match {
case Literal(v) => Some(v)
case Apply(
TypeApply(
meth@Select(_,_),
List(elemType)),
members)
if (definitions.ArrayModule_apply.alternatives contains meth.symbol) =>
trees2consArray(members, tree.tpe)
case Apply(meth, members)
if (definitions.ArrayModule_apply.alternatives contains meth.symbol) =>
trees2consArray(members, tree.tpe)
case Typed(t, _) => tree2cons(t)
case tree =>
//println("could not convert: " + tree);
None
}
private def trees2consArray(trees: Seq[Tree], arrayType:Type)
: Option[Constant] =
{
val mems = trees.map(tree2cons)
if (mems.exists(_.isEmpty))
None
else
Some(new ArrayConstant(
mems.map(_.get).toArray,
arrayType))
}
/** An argument to an annotation. It includes a parse tree,
* and it includes a compile-time constant for the tree if possible.
*/
class AnnotationArgument(val intTree: Tree) {
def this(cons: Constant) = this(
Literal(cons).setType(cons.tpe))
@deprecated
lazy val tree = {
object reifiers extends {
val symbols: AnnotationInfos.this.type = AnnotationInfos.this
} with Reifiers
reifiers.reify(intTree)
}
val constant: Option[Constant] = tree2cons(intTree)
def isConstant = !constant.isEmpty
override def toString: String =
constant match {
case Some(cons) => cons.escapedStringValue
case None => intTree.toString
}
}
/** Typed information about an annotation. It can be attached to
* either a symbol or an annotated type.
*/
case class AnnotationInfo(
atp: Type,
args: List[AnnotationArgument],
assocs: List[(Name, AnnotationArgument)])
{
override def toString: String =
atp +
(if (args.isEmpty) ""
else args.mkString("(", ", ", ")")) +
(if (assocs.isEmpty) ""
else (assocs map { case (x, y) => x+" = "+y } mkString ("{", ", ", "}")))
/** Check whether all arguments and assocations are constants */
def isConstant =
((args forall (_.isConstant)) &&
(assocs map (_._2) forall (_.isConstant)))
/** Check whether the type or any of the arguments are erroneous */
def isErroneous = atp.isErroneous || args.exists(_.intTree.isErroneous)
/** Check whether any of the arguments mention a symbol */
def refsSymbol(sym: Symbol) =
args.exists(_.intTree.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(arg => new AnnotationArgument(subs(arg.intTree))),
assocs)
}
}
}
|