@@ -7,14 +7,17 @@ import StdNames._
7
7
import dotty .tools .dotc .ast .tpd
8
8
import scala .util .Try
9
9
import util .Spans .Span
10
+ import printing .{Showable , Printer }
11
+ import printing .Texts .Text
12
+ import annotation .internal .sharable
10
13
11
14
object Annotations {
12
15
13
16
def annotClass (tree : Tree )(using Context ) =
14
17
if (tree.symbol.isConstructor) tree.symbol.owner
15
18
else tree.tpe.typeSymbol
16
19
17
- abstract class Annotation {
20
+ abstract class Annotation extends Showable {
18
21
def tree (using Context ): Tree
19
22
20
23
def symbol (using Context ): Symbol = annotClass(tree)
@@ -26,7 +29,8 @@ object Annotations {
26
29
def derivedAnnotation (tree : Tree )(using Context ): Annotation =
27
30
if (tree eq this .tree) this else Annotation (tree)
28
31
29
- def arguments (using Context ): List [Tree ] = ast.tpd.arguments(tree)
32
+ /** All arguments to this annotation in a single flat list */
33
+ def arguments (using Context ): List [Tree ] = ast.tpd.allArguments(tree)
30
34
31
35
def argument (i : Int )(using Context ): Option [Tree ] = {
32
36
val args = arguments
@@ -44,15 +48,48 @@ object Annotations {
44
48
/** The tree evaluation has finished. */
45
49
def isEvaluated : Boolean = true
46
50
51
+ /** Normally, type map over all tree nodes of this annotation, but can
52
+ * be overridden. Returns EmptyAnnotation if type type map produces a range
53
+ * type, since ranges cannot be types of trees.
54
+ */
55
+ def mapWith (tm : TypeMap )(using Context ) =
56
+ val args = arguments
57
+ if args.isEmpty then this
58
+ else
59
+ val findDiff = new TreeAccumulator [Type ]:
60
+ def apply (x : Type , tree : Tree )(using Context ): Type =
61
+ if tm.isRange(x) then x
62
+ else
63
+ val tp1 = tm(tree.tpe)
64
+ foldOver(if tp1 =:= tree.tpe then x else tp1, tree)
65
+ val diff = findDiff(NoType , args)
66
+ if tm.isRange(diff) then EmptyAnnotation
67
+ else if diff.exists then derivedAnnotation(tm.mapOver(tree))
68
+ else this
69
+
70
+ /** Does this annotation refer to a parameter of `tl`? */
71
+ def refersToParamOf (tl : TermLambda )(using Context ): Boolean =
72
+ val args = arguments
73
+ if args.isEmpty then false
74
+ else tree.existsSubTree {
75
+ case id : Ident => id.tpe match
76
+ case TermParamRef (tl1, _) => tl eq tl1
77
+ case _ => false
78
+ case _ => false
79
+ }
80
+
81
+ /** A string representation of the annotation. Overridden in BodyAnnotation.
82
+ */
83
+ def toText (printer : Printer ): Text = printer.annotText(this )
84
+
47
85
def ensureCompleted (using Context ): Unit = tree
48
86
49
87
def sameAnnotation (that : Annotation )(using Context ): Boolean =
50
88
symbol == that.symbol && tree.sameTree(that.tree)
51
89
}
52
90
53
- case class ConcreteAnnotation (t : Tree ) extends Annotation {
91
+ case class ConcreteAnnotation (t : Tree ) extends Annotation :
54
92
def tree (using Context ): Tree = t
55
- }
56
93
57
94
abstract class LazyAnnotation extends Annotation {
58
95
protected var mySym : Symbol | (Context ?=> Symbol )
@@ -98,6 +135,7 @@ object Annotations {
98
135
if (tree eq this .tree) this else ConcreteBodyAnnotation (tree)
99
136
override def arguments (using Context ): List [Tree ] = Nil
100
137
override def ensureCompleted (using Context ): Unit = ()
138
+ override def toText (printer : Printer ): Text = " @Body"
101
139
}
102
140
103
141
class ConcreteBodyAnnotation (body : Tree ) extends BodyAnnotation {
@@ -194,6 +232,8 @@ object Annotations {
194
232
apply(defn.SourceFileAnnot , Literal (Constant (path)))
195
233
}
196
234
235
+ @ sharable val EmptyAnnotation = Annotation (EmptyTree )
236
+
197
237
def ThrowsAnnotation (cls : ClassSymbol )(using Context ): Annotation = {
198
238
val tref = cls.typeRef
199
239
Annotation (defn.ThrowsAnnot .typeRef.appliedTo(tref), Ident (tref))
0 commit comments