summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
blob: 1ba014d19db0ce5f0d2d2b028859c5f83f36e92e (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
/* NSC -- new Scala compiler
 * Copyright 2007-2013 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala
package reflect
package internal

/** Additions to the type checker that can be added at
 *  run time.  Typically these are added by
 *  compiler plugins. */
trait AnnotationCheckers {
  self: SymbolTable =>


  /** An additional checker for annotations on types.
   *  Typically these are registered by compiler plugins
   *  with the addAnnotationChecker method. */
  trait AnnotationChecker {

    /**
     * Selectively activate this annotation checker. When using both an annotation checker
     * and an analyzer plugin, it is common to run both of them only during selected
     * compiler phases. See documentation in AnalyzerPlugin.isActive.
     */
    def isActive(): Boolean = true

    /** Check the annotations on two types conform. */
    def annotationsConform(tpe1: Type, tpe2: Type): Boolean

    /** Refine the computed least upper bound of a list of types.
     *  All this should do is add annotations. */
    def annotationsLub(tp: Type, ts: List[Type]): Type = tp

    /** Refine the computed greatest lower bound of a list of types.
     *  All this should do is add annotations. */
    def annotationsGlb(tp: Type, ts: List[Type]): Type = tp

    /** Refine the bounds on type parameters to the given type arguments. */
    def adaptBoundsToAnnotations(bounds: List[TypeBounds], tparams: List[Symbol],
                                 targs: List[Type]): List[TypeBounds] = bounds

    /**
     * Modify the type that has thus far been inferred for a tree. All this should
     * do is add annotations.
     */
    @deprecated("Create an AnalyzerPlugin and use pluginsTyped", "2.10.1")
    def addAnnotations(tree: Tree, tpe: Type): Type = tpe

    /**
     * Decide whether this analyzer plugin can adapt a tree that has an annotated type to the
     * given type tp, taking into account the given mode (see method adapt in trait Typers).
     */
    @deprecated("Create an AnalyzerPlugin and use canAdaptAnnotations", "2.10.1")
    def canAdaptAnnotations(tree: Tree, mode: Mode, pt: Type): Boolean = false

    /**
     * Adapt a tree that has an annotated type to the given type tp, taking into account the given
     * mode (see method adapt in trait Typers).
     *
     * An implementation cannot rely on canAdaptAnnotations being called before. If the implementing
     * class cannot do the adapting, it should return the tree unchanged.
     */
    @deprecated("Create an AnalyzerPlugin and use adaptAnnotations", "2.10.1")
    def adaptAnnotations(tree: Tree, mode: Mode, pt: Type): Tree = tree

    /**
     * Adapt the type of a return expression. The decision of a typer plugin whether the type
     * should be adapted is based on the type of the expression which is returned, as well as the
     * result type of the method (pt).
     *
     * By default, this method simply returns the passed `default` type.
     */
    @deprecated("Create an AnalyzerPlugin and use pluginsTypedReturn. Note: the 'tree' argument here is\n"+
                "the 'expr' of a Return tree; 'pluginsTypedReturn' takes the Return tree itself as argument", "2.10.1")
    def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type = default
  }

  // Syncnote: Annotation checkers inaccessible to reflection, so no sync in var necessary.

  /** The list of annotation checkers that have been registered */
  private var annotationCheckers: List[AnnotationChecker] = Nil

  /** Register an annotation checker.  Typically these are added by compiler plugins. */
  def addAnnotationChecker(checker: AnnotationChecker) {
    if (!(annotationCheckers contains checker))
      annotationCheckers = checker :: annotationCheckers
  }

  /** Remove all annotation checkers */
  def removeAllAnnotationCheckers() {
    annotationCheckers = Nil
  }

  /** @see AnnotationChecker.annotationsConform */
  def annotationsConform(tp1: Type, tp2: Type): Boolean =
    if (annotationCheckers.isEmpty || (tp1.annotations.isEmpty && tp2.annotations.isEmpty)) true
    else annotationCheckers.forall(checker => {
      !checker.isActive() || checker.annotationsConform(tp1,tp2)
    })

  /** @see AnnotationChecker.annotationsLub */
  def annotationsLub(tpe: Type, ts: List[Type]): Type =
    if (annotationCheckers.isEmpty) tpe
    else annotationCheckers.foldLeft(tpe)((tpe, checker) =>
      if (!checker.isActive()) tpe else checker.annotationsLub(tpe, ts))

  /** @see AnnotationChecker.annotationsGlb */
  def annotationsGlb(tpe: Type, ts: List[Type]): Type =
    if (annotationCheckers.isEmpty) tpe
    else annotationCheckers.foldLeft(tpe)((tpe, checker) =>
      if (!checker.isActive()) tpe else checker.annotationsGlb(tpe, ts))

  /** @see AnnotationChecker.adaptBoundsToAnnotations */
  def adaptBoundsToAnnotations(bounds: List[TypeBounds], tparams: List[Symbol],
                               targs: List[Type]): List[TypeBounds] =
    if (annotationCheckers.isEmpty) bounds
    else annotationCheckers.foldLeft(bounds)((bounds, checker) =>
      if (!checker.isActive()) bounds else checker.adaptBoundsToAnnotations(bounds, tparams, targs))


  /* The following methods will be removed with the deprecated methods is AnnotationChecker. */

  def addAnnotations(tree: Tree, tpe: Type): Type =
    if (annotationCheckers.isEmpty) tpe
    else annotationCheckers.foldLeft(tpe)((tpe, checker) =>
      if (!checker.isActive()) tpe else checker.addAnnotations(tree, tpe))

  def canAdaptAnnotations(tree: Tree, mode: Mode, pt: Type): Boolean =
    if (annotationCheckers.isEmpty) false
    else annotationCheckers.exists(checker => {
      checker.isActive() && checker.canAdaptAnnotations(tree, mode, pt)
    })

  def adaptAnnotations(tree: Tree, mode: Mode, pt: Type): Tree =
    if (annotationCheckers.isEmpty) tree
    else annotationCheckers.foldLeft(tree)((tree, checker) =>
      if (!checker.isActive()) tree else checker.adaptAnnotations(tree, mode, pt))

  def adaptTypeOfReturn(tree: Tree, pt: Type, default: => Type): Type =
    if (annotationCheckers.isEmpty) default
    else annotationCheckers.foldLeft(default)((tpe, checker) =>
      if (!checker.isActive()) tpe else checker.adaptTypeOfReturn(tree, pt, tpe))
}