Skip to content

Commit 3a3ecf7

Browse files
dwijnandsmarter
andcommitted
Support use-site meta-annotations
Co-Authored-By: Guillaume Martres <[email protected]>
1 parent 7b9c1a8 commit 3a3ecf7

File tree

6 files changed

+70
-8
lines changed

6 files changed

+70
-8
lines changed

compiler/src/dotty/tools/dotc/core/Annotations.scala

+13
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ object Annotations {
8787
def sameAnnotation(that: Annotation)(using Context): Boolean =
8888
symbol == that.symbol && tree.sameTree(that.tree)
8989

90+
def hasOneOfMetaAnnotation(metaSyms: Symbol*)(using Context): Boolean =
91+
def recTp(tp: Type): Boolean = tp.dealiasKeepAnnots match
92+
case AnnotatedType(parent, metaAnnot) => metaSyms.exists(metaAnnot.matches) || recTp(parent)
93+
case _ => false
94+
def rec(tree: Tree): Boolean = methPart(tree) match
95+
case New(tpt) => rec(tpt)
96+
case Select(qual, _) => rec(qual)
97+
case Annotated(arg, metaAnnot) => metaSyms.exists(metaAnnot.tpe.classSymbol.derivesFrom) || rec(arg)
98+
case t @ Ident(_) => recTp(t.tpe)
99+
case Typed(expr, _) => rec(expr)
100+
case _ => false
101+
metaSyms.exists(symbol.hasAnnotation) || rec(tree)
102+
90103
/** Operations for hash-consing, can be overridden */
91104
def hash: Int = System.identityHashCode(this)
92105
def eql(that: Annotation) = this eq that

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
package dotty.tools.dotc
1+
package dotty.tools
2+
package dotc
23
package transform
34

45
import dotty.tools.dotc.ast.{Trees, tpd, untpd, desugar}
@@ -186,12 +187,8 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
186187
private def removeUnwantedAnnotations(sym: Symbol, metaAnnotSym: Symbol,
187188
metaAnnotSymBackup: Symbol, keepIfNoRelevantAnnot: Boolean)(using Context): Unit =
188189
def shouldKeep(annot: Annotation): Boolean =
189-
val annotSym = annot.symbol
190-
annotSym.hasAnnotation(metaAnnotSym)
191-
|| annotSym.hasAnnotation(metaAnnotSymBackup)
192-
|| (keepIfNoRelevantAnnot && {
193-
!annotSym.annotations.exists(metaAnnot => defn.FieldAccessorMetaAnnots.contains(metaAnnot.symbol))
194-
})
190+
annot.hasOneOfMetaAnnotation(metaAnnotSym, metaAnnotSymBackup)
191+
|| keepIfNoRelevantAnnot && !annot.hasOneOfMetaAnnotation(defn.FieldAccessorMetaAnnots.toList*)
195192
if sym.annotations.nonEmpty then
196193
sym.filterAnnotations(shouldKeep(_))
197194

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ object SymUtils:
271271
self.isAllOf(EnumCase, butNot = JavaDefined)
272272

273273
def annotationsCarrying(meta: ClassSymbol)(using Context): List[Annotation] =
274-
self.annotations.filter(_.symbol.hasAnnotation(meta))
274+
self.annotations.filter(_.hasOneOfMetaAnnotation(meta))
275275

276276
def withAnnotationsCarrying(from: Symbol, meta: ClassSymbol)(using Context): self.type = {
277277
self.addAnnotations(from.annotationsCarrying(meta))

tests/run/i12492.check

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
inspecting field brandName
2+
@MyColumnBase(name="BRAND_NAME")
3+
inspecting field companyName
4+
@MyColumnBase(name="COMPANY_NAME")
5+
inspecting method companyName
6+
inspecting method brandName
7+
inspecting constructor MyTable
8+
inspecting param brandName
9+
inspecting param companyName

tests/run/i12492/MyColumnBase.java

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import java.lang.annotation.Retention;
2+
import java.lang.annotation.RetentionPolicy;
3+
4+
@Retention(RetentionPolicy.RUNTIME)
5+
public @interface MyColumnBase {
6+
String name() default "";
7+
}

tests/run/i12492/MyTable.scala

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import scala.annotation.meta.field
2+
3+
type MyColumn = MyColumnBase @field
4+
5+
class MyTable(
6+
@(MyColumnBase @field)(name="BRAND_NAME")
7+
val brandName: String,
8+
@MyColumn(name="COMPANY_NAME")
9+
val companyName: String,
10+
)
11+
12+
object Test:
13+
def main(args: Array[String]): Unit =
14+
val clasz = classOf[MyTable]
15+
16+
for (m <- clasz.getDeclaredFields) {
17+
m.setAccessible(true)
18+
println(s"inspecting field ${m.getName}")
19+
for a <- m.getAnnotations() do
20+
println(a)
21+
}
22+
23+
for (m <- clasz.getDeclaredMethods) {
24+
m.setAccessible(true)
25+
println(s"inspecting method ${m.getName}")
26+
for a <- m.getAnnotations() do
27+
println(a)
28+
}
29+
30+
for c <- clasz.getDeclaredConstructors do
31+
c.setAccessible(true)
32+
println(s"inspecting constructor ${c.getName}")
33+
for p <- c.getParameters do
34+
println(s"inspecting param ${p.getName}")
35+
for a <- p.getAnnotations do
36+
println(s"annotation $a")

0 commit comments

Comments
 (0)