@@ -7,14 +7,17 @@ import StdNames._
77import dotty .tools .dotc .ast .tpd
88import scala .util .Try
99import util .Spans .Span
10+ import printing .{Showable , Printer }
11+ import printing .Texts .Text
12+ import annotation .internal .sharable
1013
1114object Annotations {
1215
1316 def annotClass (tree : Tree )(using Context ) =
1417 if (tree.symbol.isConstructor) tree.symbol.owner
1518 else tree.tpe.typeSymbol
1619
17- abstract class Annotation {
20+ abstract class Annotation extends Showable {
1821 def tree (using Context ): Tree
1922
2023 def symbol (using Context ): Symbol = annotClass(tree)
@@ -26,7 +29,8 @@ object Annotations {
2629 def derivedAnnotation (tree : Tree )(using Context ): Annotation =
2730 if (tree eq this .tree) this else Annotation (tree)
2831
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)
3034
3135 def argument (i : Int )(using Context ): Option [Tree ] = {
3236 val args = arguments
@@ -44,15 +48,48 @@ object Annotations {
4448 /** The tree evaluation has finished. */
4549 def isEvaluated : Boolean = true
4650
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+
4785 def ensureCompleted (using Context ): Unit = tree
4886
4987 def sameAnnotation (that : Annotation )(using Context ): Boolean =
5088 symbol == that.symbol && tree.sameTree(that.tree)
5189 }
5290
53- case class ConcreteAnnotation (t : Tree ) extends Annotation {
91+ case class ConcreteAnnotation (t : Tree ) extends Annotation :
5492 def tree (using Context ): Tree = t
55- }
5693
5794 abstract class LazyAnnotation extends Annotation {
5895 protected var mySym : Symbol | (Context ?=> Symbol )
@@ -98,6 +135,7 @@ object Annotations {
98135 if (tree eq this .tree) this else ConcreteBodyAnnotation (tree)
99136 override def arguments (using Context ): List [Tree ] = Nil
100137 override def ensureCompleted (using Context ): Unit = ()
138+ override def toText (printer : Printer ): Text = " @Body"
101139 }
102140
103141 class ConcreteBodyAnnotation (body : Tree ) extends BodyAnnotation {
@@ -194,6 +232,8 @@ object Annotations {
194232 apply(defn.SourceFileAnnot , Literal (Constant (path)))
195233 }
196234
235+ @ sharable val EmptyAnnotation = Annotation (EmptyTree )
236+
197237 def ThrowsAnnotation (cls : ClassSymbol )(using Context ): Annotation = {
198238 val tref = cls.typeRef
199239 Annotation (defn.ThrowsAnnot .typeRef.appliedTo(tref), Ident (tref))
0 commit comments