All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dotc.transform.RepeatableAnnotations.scala Maven / Gradle / Ivy

There is a newer version: 3.6.4-RC1-bin-20241220-0bfa1af-NIGHTLY
Show newest version
package dotty.tools.dotc
package transform

import core.*
import ast.tpd.*
import Contexts.*
import MegaPhase.*
import Annotations.*
import Symbols.defn
import Constants.*
import Types.*
import Decorators.*
import Flags.*

import scala.collection.mutable

class RepeatableAnnotations extends MiniPhase:

  override def phaseName: String = RepeatableAnnotations.name

  override def description: String = RepeatableAnnotations.description

  override def transformTypeDef(tree: TypeDef)(using Context): Tree = transformDef(tree)
  override def transformValDef(tree: ValDef)(using Context): Tree = transformDef(tree)
  override def transformDefDef(tree: DefDef)(using Context): Tree = transformDef(tree)

  private def transformDef(tree: DefTree)(using Context) =
    val annotations = tree.symbol.annotations
    if (!annotations.isEmpty) then
      tree.symbol.annotations = aggregateAnnotations(tree.symbol.annotations)
    tree

  private def aggregateAnnotations(annotations: Seq[Annotation])(using Context): List[Annotation] =
    val annsByType = stableGroupBy(annotations, _.symbol)
    annsByType.flatMap {
      case (_, a :: Nil) => a :: Nil
      case (sym, anns) if sym.is(JavaDefined) =>
        sym.getAnnotation(defn.JavaRepeatableAnnot).flatMap(_.argumentConstant(0)) match
          case Some(Constant(containerTpe: Type)) =>
            val clashingAnns = annsByType.getOrElse(containerTpe.classSymbol, Nil)
            if clashingAnns.nonEmpty then
              // this is the same error javac would raise in this case
              val pos = clashingAnns.head.tree.srcPos
              report.error("Container must not be present at the same time as the element it contains", pos)
              Nil
            else
              val aggregated = JavaSeqLiteral(anns.map(_.tree).toList, TypeTree(sym.typeRef))
              Annotation(containerTpe, NamedArg("value".toTermName, aggregated), sym.span) :: Nil
          case _ =>
            val pos = anns.head.tree.srcPos
            report.error("Not repeatable annotation repeated", pos)
            Nil
      case (_, anns) => anns
    }.toList

  private def stableGroupBy[A, K](ins: Seq[A], f: A => K): scala.collection.MapView[K, List[A]] =
    val out = new mutable.LinkedHashMap[K, mutable.ListBuffer[A]]()
    for (in <- ins) {
      val buffer = out.getOrElseUpdate(f(in), new mutable.ListBuffer)
      buffer += in
    }
    out.view.mapValues(_.toList)

object RepeatableAnnotations:
  val name: String = "repeatableAnnotations"
  val description: String = "aggregate repeatable annotations"




© 2015 - 2025 Weber Informatics LLC | Privacy Policy