diff --git a/library/src/scala/annotation/constructorOnly.scala b/library/src/scala/annotation/constructorOnly.scala index 4959b7c503b6..4977de6c8c60 100644 --- a/library/src/scala/annotation/constructorOnly.scala +++ b/library/src/scala/annotation/constructorOnly.scala @@ -22,4 +22,6 @@ import scala.annotation.meta.* * class fields. But it is checked that the field is eliminated before code * is generated. */ -@param @field class constructorOnly extends scala.annotation.StaticAnnotation +@param @field +@documented +class constructorOnly extends scala.annotation.StaticAnnotation diff --git a/library/src/scala/annotation/documented.scala b/library/src/scala/annotation/documented.scala new file mode 100644 index 000000000000..0e08126750f4 --- /dev/null +++ b/library/src/scala/annotation/documented.scala @@ -0,0 +1,10 @@ +package scala.annotation + +// TODO: Write the actual scaladoc of this annotation + +// The annotation from Java is a simple hack as both have the same semantic +// meaning, only this one should be used by Scala code and the second +// annotation by Java Code +// @documented (TODO: can we make it work without breaking the cycle detection algorithm?) +@java.lang.annotation.Documented +final class documented extends StaticAnnotation diff --git a/library/src/scala/annotation/experimental.scala b/library/src/scala/annotation/experimental.scala index ee91a6408b4b..761c51fe0dd1 100644 --- a/library/src/scala/annotation/experimental.scala +++ b/library/src/scala/annotation/experimental.scala @@ -7,5 +7,6 @@ import language.experimental.captureChecking * @see [[https://dotty.epfl.ch/docs/reference/other-new-features/experimental-defs]] * @syntax markdown */ +@documented final class experimental(message: String) extends StaticAnnotation: def this() = this("") diff --git a/library/src/scala/annotation/static.scala b/library/src/scala/annotation/static.scala index dc40ab9f3ac2..1c1e7949722f 100644 --- a/library/src/scala/annotation/static.scala +++ b/library/src/scala/annotation/static.scala @@ -12,4 +12,5 @@ import scala.annotation.meta.* @beanSetter @param @setter +@documented final class static extends StaticAnnotation diff --git a/library/src/scala/annotation/targetName.scala b/library/src/scala/annotation/targetName.scala index 17945fa86fb7..f5886eace6c2 100644 --- a/library/src/scala/annotation/targetName.scala +++ b/library/src/scala/annotation/targetName.scala @@ -7,4 +7,5 @@ import language.experimental.captureChecking * definition, its implementation will use the name `extname` instead of * the regular name. */ +@documented final class targetName(name: String) extends StaticAnnotation diff --git a/library/src/scala/annotation/threadUnsafe.scala b/library/src/scala/annotation/threadUnsafe.scala index dd87e74f3048..93433e41cbd8 100644 --- a/library/src/scala/annotation/threadUnsafe.scala +++ b/library/src/scala/annotation/threadUnsafe.scala @@ -6,4 +6,5 @@ import language.experimental.captureChecking * When this annotation is used, the initialization of the lazy val will use a * faster mechanism which is not thread-safe. */ +@documented final class threadUnsafe extends StaticAnnotation diff --git a/library/src/scala/annotation/varargs.scala b/library/src/scala/annotation/varargs.scala index 967e2df00f6f..c38b018d516d 100644 --- a/library/src/scala/annotation/varargs.scala +++ b/library/src/scala/annotation/varargs.scala @@ -18,4 +18,5 @@ import scala.language.`2.13` * Java varargs-style forwarder method for interop. This annotation can * only be applied to methods with repeated parameters. */ +@documented final class varargs extends scala.annotation.StaticAnnotation diff --git a/library/src/scala/caps/package.scala b/library/src/scala/caps/package.scala index 2cd75efdf197..35ea66dec55b 100644 --- a/library/src/scala/caps/package.scala +++ b/library/src/scala/caps/package.scala @@ -3,7 +3,7 @@ package caps import language.experimental.captureChecking -import annotation.{experimental, compileTimeOnly, retainsCap} +import annotation.{experimental, documented, compileTimeOnly, retainsCap} /** * Base trait for classes that represent capabilities in the @@ -119,10 +119,10 @@ final class reserve extends annotation.StaticAnnotation /** Allowed only for source versions up to 3.7: * An annotation on parameters `x` stating that the method's body makes * use of the reach capability `x*`. Consequently, when calling the method - * we need to charge the deep capture set of the actual argiment to the + * we need to charge the deep capture set of the actual argument to the * environment. */ -@experimental +@experimental @documented final class use extends annotation.StaticAnnotation /** A trait that used to allow expressing existential types. Replaced by diff --git a/library/src/scala/specialized.scala b/library/src/scala/specialized.scala index f673fb6a3bb9..394bc260efa8 100644 --- a/library/src/scala/specialized.scala +++ b/library/src/scala/specialized.scala @@ -14,6 +14,8 @@ package scala import scala.language.`2.13` +import scala.annotation.documented + import Specializable._ /** Annotate type parameters on which code should be automatically @@ -30,6 +32,7 @@ import Specializable._ */ // class tspecialized[T](group: Group[T]) extends scala.annotation.StaticAnnotation { +@documented final class specialized(group: SpecializedGroup) extends scala.annotation.StaticAnnotation { def this(types: Specializable*) = this(new Group(types.toList)) def this() = this(Primitives) diff --git a/library/src/scala/throws.scala b/library/src/scala/throws.scala index 898c745a4804..a1fec6c3f033 100644 --- a/library/src/scala/throws.scala +++ b/library/src/scala/throws.scala @@ -14,6 +14,8 @@ package scala import scala.language.`2.13` +import scala.annotation.documented + /** * Annotation for specifying the exceptions thrown by a method. * For example: @@ -25,6 +27,7 @@ import scala.language.`2.13` * } * }}} */ +@documented final class throws[T <: Throwable](cause: String = "") extends scala.annotation.StaticAnnotation { def this(clazz: Class[T]) = this("") } diff --git a/library/src/scala/transient.scala b/library/src/scala/transient.scala index 3ca34fba9f69..1094c043ac7a 100644 --- a/library/src/scala/transient.scala +++ b/library/src/scala/transient.scala @@ -13,7 +13,9 @@ package scala import scala.language.`2.13` + +import scala.annotation.documented import scala.annotation.meta._ -@field +@field @documented final class transient extends scala.annotation.StaticAnnotation diff --git a/library/src/scala/volatile.scala b/library/src/scala/volatile.scala index 75b615ee6c7d..4369d15601af 100644 --- a/library/src/scala/volatile.scala +++ b/library/src/scala/volatile.scala @@ -13,7 +13,9 @@ package scala import scala.language.`2.13` + +import scala.annotation.documented import scala.annotation.meta._ -@field +@field @documented final class volatile extends scala.annotation.StaticAnnotation diff --git a/project/Build.scala b/project/Build.scala index f7ab11833574..9cdfe05a1682 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1138,6 +1138,7 @@ object Build { file(s"${baseDirectory.value}/src/scala/annotation/retainsByName.scala"), file(s"${baseDirectory.value}/src/scala/annotation/threadUnsafe.scala"), file(s"${baseDirectory.value}/src/scala/annotation/constructorOnly.scala"), + file(s"${baseDirectory.value}/src/scala/annotation/documented.scala"), file(s"${baseDirectory.value}/src/scala/annotation/experimental.scala"), file(s"${baseDirectory.value}/src/scala/annotation/MacroAnnotation.scala"), file(s"${baseDirectory.value}/src/scala/annotation/alpha.scala"), @@ -1276,6 +1277,7 @@ object Build { file(s"${baseDirectory.value}/src/scala/annotation/retainsByName.scala"), file(s"${baseDirectory.value}/src/scala/annotation/threadUnsafe.scala"), file(s"${baseDirectory.value}/src/scala/annotation/constructorOnly.scala"), + file(s"${baseDirectory.value}/src/scala/annotation/documented.scala"), file(s"${baseDirectory.value}/src/scala/annotation/experimental.scala"), file(s"${baseDirectory.value}/src/scala/annotation/MacroAnnotation.scala"), file(s"${baseDirectory.value}/src/scala/annotation/alpha.scala"), diff --git a/scaladoc-testcases/src/tests/namedTuples.scala b/scaladoc-testcases/src/tests/namedTuples.scala index 30a83e7e01b0..47aca287c4ba 100644 --- a/scaladoc-testcases/src/tests/namedTuples.scala +++ b/scaladoc-testcases/src/tests/namedTuples.scala @@ -1,6 +1,5 @@ package tests.namedTuples -import language.experimental.namedTuples import NamedTuple.* type Person = (name: String, age: Int) diff --git a/scaladoc-testcases/src/tests/refinedFunctionTypes.scala b/scaladoc-testcases/src/tests/refinedFunctionTypes.scala index d978a0ea2264..c2bcf347e181 100644 --- a/scaladoc-testcases/src/tests/refinedFunctionTypes.scala +++ b/scaladoc-testcases/src/tests/refinedFunctionTypes.scala @@ -4,29 +4,29 @@ package refinedFunctionTypes import annotation.experimental @experimental -infix type $throws[R, +E <: Exception] = CanThrow[E] ?=> R +infix type $throws[R, +E <: Exception] = CanThrow[E] ?=> R //expected: @experimental infix type $throws[R, +E <: Exception] = CanThrow[E] ?=> R @experimental -infix type $throws2[+E <: Exception] = (c: CanThrow[E]) ?=> c.type +infix type $throws2[+E <: Exception] = (c: CanThrow[E]) ?=> c.type //expected: @experimental infix type $throws2[+E <: Exception] = (c: CanThrow[E]) ?=> c.type @experimental -infix type $throws3[+E <: Exception] = [T] => (c: CanThrow[E]) ?=> c.type +infix type $throws3[+E <: Exception] = [T] => (c: CanThrow[E]) ?=> c.type //expected: @experimental infix type $throws3[+E <: Exception] = [T] => (c: CanThrow[E]) ?=> c.type @experimental -infix type $throws4[+E <: Exception] = [T] => (c: CanThrow[E]) ?=> T //expected: infix type $throws4[+E <: Exception] = [T] => CanThrow[E] ?=> T +infix type $throws4[+E <: Exception] = [T] => (c: CanThrow[E]) ?=> T //expected: @experimental infix type $throws4[+E <: Exception] = [T] => CanThrow[E] ?=> T type TA1 = (a: Int, b: (Boolean, String)) => List[(a.type, b.type)] type TA2 = (a: Int, b: (Boolean, String)) ?=> List[Boolean] @experimental -type TB0 = [R, E <: Exception] =>> PolyFunction { def apply[T](c: CanThrow[E]): R; } //expected: type TB0[R, E <: Exception] = [T] => CanThrow[E] => R +type TB0 = [R, E <: Exception] =>> PolyFunction { def apply[T](c: CanThrow[E]): R; } //expected: @experimental type TB0[R, E <: Exception] = [T] => CanThrow[E] => R @experimental -type TB1 = [R, E <: Exception] =>> PolyFunction { def apply[T](c: CanThrow[E], y: c.type): R; } //expected: type TB1[R, E <: Exception] = [T] => (c: CanThrow[E], y: c.type) => R +type TB1 = [R, E <: Exception] =>> PolyFunction { def apply[T](c: CanThrow[E], y: c.type): R; } //expected: @experimental type TB1[R, E <: Exception] = [T] => (c: CanThrow[E], y: c.type) => R @experimental -type TB2 = [R, E <: Exception] =>> PolyFunction { def apply[T](using c: CanThrow[E]): c.type; } //expected: type TB2[R, E <: Exception] = [T] => (c: CanThrow[E]) ?=> c.type +type TB2 = [R, E <: Exception] =>> PolyFunction { def apply[T](using c: CanThrow[E]): c.type; } //expected: @experimental type TB2[R, E <: Exception] = [T] => (c: CanThrow[E]) ?=> c.type type TC1 = [T] => (a: T) => T //expected: type TC1 = [T] => T => T diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala index c96b6899501d..d9b6c1e157e4 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala @@ -41,29 +41,15 @@ trait BasicSupport: def documentation = parseComment(sym.docstring.getOrElse(""), sym.tree) def getAnnotations(): List[Annotation] = - // Custom annotations should be documented only if annotated by @java.lang.annotation.Documented - // We allow also some special cases - val fqNameAllowlist0 = Set( - "scala.specialized", - "scala.throws", - "scala.transient", - "scala.volatile", - "scala.annotation.experimental", - "scala.annotation.constructorOnly", - "scala.annotation.static", - "scala.annotation.targetName", - "scala.annotation.threadUnsafe", - "scala.annotation.varargs", - ) - val fqNameAllowlist = - if ccEnabled then - fqNameAllowlist0 + CaptureDefs.useAnnotFullName - else fqNameAllowlist0 - val documentedSymbol = summon[Quotes].reflect.Symbol.requiredClass("java.lang.annotation.Documented") - val annotations = sym.annotations.filter { a => - a.tpe.typeSymbol.hasAnnotation(documentedSymbol) || fqNameAllowlist.contains(a.symbol.fullName) - } - annotations.map(parseAnnotation).reverse + sym.annotations + .filter(a => a.tpe.typeSymbol.isDocumented) + .map(parseAnnotation) + .reverse + + def isDocumented: Boolean = + val javaDocumentedSymbol = reflect.Symbol.requiredClass("java.lang.annotation.Documented") + val scalaDocumentedSymbol = reflect.Symbol.requiredClass("scala.annotation.documented") + sym.hasAnnotation(scalaDocumentedSymbol) || sym.hasAnnotation(javaDocumentedSymbol) def isDeprecated(): Option[Annotation] = sym.annotations.find { a =>