From e25232d5b4fdc1ae7bc5a44ad06e31a00699dbaf Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 3 Aug 2014 20:50:37 +0200 Subject: Annotation decorators for symbols Added decorators for symbols that can query specific annotations and annotation arguments (for now, -deprecated and -migration are added) --- src/dotty/tools/dotc/ast/TreeInfo.scala | 12 ++++++++-- src/dotty/tools/dotc/core/Annotations.scala | 33 ++++++++++++++++++++++++++ src/dotty/tools/dotc/core/SymDenotations.scala | 9 ++----- 3 files changed, 45 insertions(+), 9 deletions(-) (limited to 'src/dotty/tools/dotc') diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index cc3e53abc..174de4d46 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -103,11 +103,19 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => /** The number of arguments in an application */ def numArgs(tree: Tree): Int = unsplice(tree) match { case Apply(fn, args) => numArgs(fn) + args.length - case TypeApply(fn, args) => numArgs(fn) - case Block(stats, expr) => numArgs(expr) + case TypeApply(fn, _) => numArgs(fn) + case Block(_, expr) => numArgs(expr) case _ => 0 } + /** The (last) list of arguments of an application */ + def arguments(tree: Tree): List[Tree] = unsplice(tree) match { + case Apply(_, args) => args + case TypeApply(fn, _) => arguments(fn) + case Block(_, expr) => arguments(expr) + case _ => Nil + } + /** Is tree a self constructor call this(...)? I.e. a call to a constructor of the * same object? */ diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index b4b7ebd24..f67381ddc 100644 --- a/src/dotty/tools/dotc/core/Annotations.scala +++ b/src/dotty/tools/dotc/core/Annotations.scala @@ -2,6 +2,7 @@ package dotty.tools.dotc package core import Symbols._, Types._, util.Positions._, Contexts._, Constants._, ast.tpd._ +import config.ScalaVersion object Annotations { @@ -15,6 +16,14 @@ object Annotations { def derivedAnnotation(tree: Tree)(implicit ctx: Context) = if (tree eq this.tree) this else Annotation(tree) + + def arguments(implicit ctx: Context) = ast.tpd.arguments(tree) + def argument(i: Int)(implicit ctx: Context): Option[Tree] = { + val args = arguments + if (i < args.length) Some(args(i)) else None + } + def argumentConstant(i: Int)(implicit ctx: Context): Option[Constant] = + for (ConstantType(c) <- argument(i) map (_.tpe)) yield c } case class ConcreteAnnotation(t: Tree) extends Annotation { @@ -69,4 +78,28 @@ object Annotations { val tref = cls.typeRef Annotation(defn.ThrowsAnnot.typeRef.appliedTo(tref), Ident(tref)) } + + /** A decorator that provides queries for specific annotations + * of a symbol. + */ + implicit class AnnotInfo(val sym: Symbol) extends AnyVal { + + def isDeprecated(implicit ctx: Context) = + sym.hasAnnotation(defn.DeprecatedAnnot) + + def deprecationMessage(implicit ctx: Context) = + for (annot <- sym.getAnnotation(defn.DeprecatedAnnot); + arg <- annot.argumentConstant(0)) + yield arg.stringValue + + def migrationVersion(implicit ctx: Context) = + for (annot <- sym.getAnnotation(defn.MigrationAnnot); + arg <- annot.argumentConstant(1)) + yield ScalaVersion.parse(arg.stringValue) + + def migrationMessage(implicit ctx: Context) = + for (annot <- sym.getAnnotation(defn.MigrationAnnot); + arg <- annot.argumentConstant(0)) + yield ScalaVersion.parse(arg.stringValue) + } } \ No newline at end of file diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 91a8e4345..fcc01503f 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -200,14 +200,9 @@ object SymDenotations { dropOtherAnnotations(annotations, cls).nonEmpty /** Optionally, the arguments of the first annotation matching the given class symbol */ - final def getAnnotationArgs(cls: Symbol)(implicit ctx: Context): Option[List[tpd.Tree]] = + final def getAnnotation(cls: Symbol)(implicit ctx: Context): Option[Annotation] = dropOtherAnnotations(annotations, cls) match { - case annot :: _ => - Some( - annot.tree match { - case Trees.Apply(_, args) => args - case _ => Nil - }) + case annot :: _ => Some(annot) case nil => None } -- cgit v1.2.3