Skip to content

Commit c5ff0b2

Browse files
committed
Print annotation in decompiler
1 parent 39c69c2 commit c5ff0b2

File tree

8 files changed

+119
-31
lines changed

8 files changed

+119
-31
lines changed

library/src/scala/tasty/util/ShowSourceCode.scala

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
6565
printImportSelectors(selectors)
6666

6767
case cdef @ ClassDef(name, DefDef(_, targs, argss, _, _), parents, self, stats) =>
68+
printDefAnnotations(cdef)
69+
6870
val flags = cdef.flags
6971
if (flags.isFinal && !flags.isObject) this += "final "
7072
if (flags.isCase) this += "case "
@@ -146,11 +148,14 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
146148
}
147149
this
148150

149-
case tdef@TypeDef(name, rhs) =>
151+
case tdef @ TypeDef(name, rhs) =>
152+
printDefAnnotations(tdef)
150153
this += "type "
151154
printTargDef(tdef)
152155

153-
case vdef@ValDef(name, tpt, rhs) =>
156+
case vdef @ ValDef(name, tpt, rhs) =>
157+
printDefAnnotations(vdef)
158+
154159
val flags = vdef.flags
155160
if (flags.isOverride) this += "override "
156161

@@ -201,7 +206,9 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
201206
printTree(cond)
202207
this += ")"
203208

204-
case ddef@DefDef(name, targs, argss, tpt, rhs) =>
209+
case ddef @ DefDef(name, targs, argss, tpt, rhs) =>
210+
printDefAnnotations(ddef)
211+
205212
val flags = ddef.flags
206213
if (flags.isOverride) sb.append("override ")
207214

@@ -220,8 +227,16 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
220227
}
221228
this
222229

223-
case tree@Term.Ident(name) =>
224-
printType(tree.tpe)
230+
case tree @ Term.Ident(name) =>
231+
tree.tpe match {
232+
case Type.SymRef(_, Types.EmptyPrefix()) | Type.TermRef(_, Types.EmptyPrefix()) => this += name
233+
case Type.SymRef(_, prefix) =>
234+
printTypeOrBound(prefix)
235+
this += "." += name
236+
case Type.TermRef(_, prefix) =>
237+
printTypeOrBound(prefix)
238+
this += "." += name
239+
}
225240

226241
case Term.Select(qual, name, sig) =>
227242
printTree(qual)
@@ -272,7 +287,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
272287
this += "("
273288
printTree(term)
274289
this += ": "
275-
printTypeTree(tpt)
290+
printTypeTree(tpt, isFullType = true)
276291
this += ")"
277292
}
278293

@@ -516,6 +531,19 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
516531
this += ")"
517532
}
518533

534+
def printAnnotations(trees: List[Term]): Buffer = {
535+
def printSeparated(list: List[Term]): Unit = list match {
536+
case Nil =>
537+
case x :: Nil => printAnnotation(x)
538+
case x :: xs =>
539+
printAnnotation(x)
540+
this += " "
541+
printSeparated(xs)
542+
}
543+
printSeparated(trees)
544+
this
545+
}
546+
519547
def printArgDef(arg: ValDef): Unit = {
520548
val ValDef(name, tpt, rhs) = arg
521549
this += name += ": "
@@ -614,20 +642,20 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
614642
printTypeTree(tpt)
615643
}
616644

617-
def printTypeTree(tree: TypeTree): Buffer = tree match {
645+
def printTypeTree(tree: TypeTree, isFullType: Boolean = true): Buffer = tree match {
618646
case TypeTree.Synthetic() =>
619-
printType(tree.tpe)
647+
printType(tree.tpe, isFullType)
620648
tree.tpe match {
621649
case tpe @ Type.TypeRef(name, _) if name.endsWith("$") => this += ".type"
622650
case tpe => this
623651
}
624652

625653
case TypeTree.TypeIdent(name) =>
626-
printType(tree.tpe)
654+
printType(tree.tpe, isFullType)
627655

628656
case TypeTree.TypeSelect(qual, name) =>
629657
(qual: Any) match {
630-
case qual @ TypeTree.TypeIdent(_) => printTypeTree(qual) // FIXME: qual is of type Tree buy we are getting a TypeTree qualifier
658+
case qual @ TypeTree.TypeIdent(_) => printTypeTree(qual, isFullType = false) // FIXME: qual is of type Tree buy we are getting a TypeTree qualifier
631659
case _ => printTree(qual)
632660
}
633661
this += "." += name
@@ -654,9 +682,11 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
654682
printTypeTrees(args, ", ")
655683
this += "]"
656684

657-
case TypeTree.Annotated(tpt, annots) =>
685+
case TypeTree.Annotated(tpt, annot) =>
686+
val Annotation(ref, args) = annot
658687
printTypeTree(tpt)
659-
// TODO print annots
688+
this += " "
689+
printAnnotation(annot)
660690

661691
case TypeTree.And(left, right) =>
662692
printTypeTree(left)
@@ -686,29 +716,28 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
686716
case tpe@Type() => printType(tpe)
687717
}
688718

689-
def printType(tpe: Type): Buffer = tpe match {
719+
def printType(tpe: Type, isFullType: Boolean = true): Buffer = tpe match {
690720
case Type.ConstantType(const) =>
691721
printConstant(const)
692722

693723
case Type.SymRef(sym, prefix) =>
694724
prefix match {
695-
case Type.ThisType(Types.EmptyPackage() | Types.RootPackage()) =>
725+
case Types.EmptyPrefix() =>
696726
case prefix@Type.SymRef(ClassDef(_, _, _, _, _), _) =>
697-
printType(prefix)
727+
printType(prefix, isFullType = false)
698728
this += "#"
699729
case prefix@Type() =>
700-
printType(prefix)
730+
printType(prefix, isFullType = false)
701731
this += "."
702-
case prefix@NoPrefix() =>
703732
}
704-
printDefinitionName(sym)
733+
printDefinitionName(sym, isFullType)
705734

706735
case Type.TermRef(name, prefix) =>
707736
prefix match {
708737
case Type.ThisType(Types.EmptyPackage()) =>
709738
this += name
710739
case prefix @ Type() =>
711-
printType(prefix)
740+
printType(prefix, isFullType = false)
712741
if (name != "package")
713742
this += "." += name
714743
this
@@ -719,7 +748,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
719748
case Type.TypeRef(name, prefix) =>
720749
prefix match {
721750
case NoPrefix() | Type.ThisType(Types.EmptyPackage()) =>
722-
case prefix@Type() => printType(prefix) += "."
751+
case prefix@Type() => printType(prefix, isFullType = false) += "."
723752
}
724753
this += name.stripSuffix("$")
725754

@@ -734,7 +763,10 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
734763
this += "]"
735764

736765
case Type.AnnotatedType(tp, annot) =>
766+
val Annotation(ref, args) = annot
737767
printType(tp)
768+
this += " "
769+
printAnnotation(annot)
738770

739771
case Type.AndType(left, right) =>
740772
printType(left)
@@ -767,14 +799,38 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
767799
case RenameSelector(Id(name), Id(newName)) => this += name += " => " += newName
768800
}
769801

770-
def printDefinitionName(sym: Definition): Buffer = sym match {
771-
case ValDef(name, _, _) => this += name
802+
def printDefinitionName(sym: Definition, isFullType: Boolean): Buffer = sym match {
803+
case ValDef(name, _, _) =>
804+
if (isFullType) this += name += ".type"
805+
else this += name
772806
case DefDef(name, _, _, _, _) => this += name
773807
case ClassDef(name, _, _, _, _) => this += name.stripSuffix("$")
774808
case TypeDef(name, _) => this += name
775809
case PackageDef(name, _) => this += name
776810
}
777811

812+
def printAnnotation(annot: Term): Buffer = {
813+
val Annotation(ref, args) = annot
814+
this += "@"
815+
printTypeTree(ref)
816+
this += "("
817+
printTrees(args, ", ")
818+
this += ")"
819+
}
820+
821+
def printDefAnnotations(definition: Definition): Buffer = {
822+
val annots = definition.annots.filter {
823+
case Annotation(annot, _) =>
824+
annot.tpe match {
825+
case Type.TypeRef(_, Type.SymRef(PackageDef("internal", _), Type.ThisType(Type.SymRef(PackageDef("annotation", _), NoPrefix())))) => false
826+
case _ => true
827+
}
828+
}
829+
printAnnotations(annots)
830+
if (annots.nonEmpty) this += " "
831+
else this
832+
}
833+
778834
def +=(x: Boolean): this.type = { sb.append(x); this }
779835
def +=(x: Byte): this.type = { sb.append(x); this }
780836
def +=(x: Short): this.type = { sb.append(x); this }
@@ -829,6 +885,13 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
829885
}
830886
}
831887

888+
private object Annotation {
889+
def unapply(arg: Tree)(implicit ctx: Context): Option[(TypeTree, List[Term])] = arg match {
890+
case Term.Apply(Term.Select(Term.New(annot), "<init>", _), args) => Some((annot, args))
891+
case _ => None
892+
}
893+
}
894+
832895
// TODO Provide some of these in scala.tasty.Tasty.scala and implement them using checks on symbols for performance
833896
private object Types {
834897

@@ -866,6 +929,13 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
866929
case _ => false
867930
}
868931
}
932+
933+
object EmptyPrefix {
934+
def unapply(tpe: TypeOrBounds)(implicit ctx: Context): Boolean = tpe match {
935+
case NoPrefix() | Type.ThisType(Types.EmptyPackage() | Types.RootPackage()) => true
936+
case _ => false
937+
}
938+
}
869939
}
870940

871941

tests/pos/i2104b.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ case class Pair[A, B](_1: A, _2: B) {
1313
scala.runtime.Statics.finalizeHash(acc, 2)
1414
}
1515
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
16-
case x$0: Pair[Pair.this.A, Pair.this.B] =>
16+
case x$0: Pair[Pair.this.A, Pair.this.B] @scala.unchecked() =>
1717
this._1.==(x$0._1).&&(this._2.==(x$0._2))
1818
case _ =>
1919
false
2020
})
2121
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
22-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[Pair[Pair.this.A, Pair.this.B]]
22+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[Pair[Pair.this.A, Pair.this.B] @scala.unchecked()]
2323
override def productArity: scala.Int = 2
2424
override def productPrefix: java.lang.String = "Pair"
2525
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleAnnot.decompiled

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/** Decompiled from out/posTestFromTasty/pos/simpleAnnot/Foo.class */
2+
class Foo() {
3+
@annot() type A = scala.Int
4+
@annot() val a: scala.Int = scala.Predef.???
5+
val b: scala.Int @annot() = scala.Predef.???
6+
def c(x: scala.Int): scala.Int = (x: x.type @annot())
7+
}
8+
/** Decompiled from out/posTestFromTasty/pos/simpleAnnot/annot.class */
9+
class annot() extends scala.annotation.Annotation

tests/pos/simpleAnnot.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
class Foo {
3+
@annot type A = Int
4+
@annot val a: Int = ???
5+
val b: Int @annot = ???
6+
def c(x: Int) = (x : @annot)
7+
}
8+
9+
class annot extends scala.annotation.Annotation

tests/pos/simpleCaseClass-1.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
case class A() {
33
override def hashCode(): scala.Int = 1914112431
44
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
5-
case x$0: A =>
5+
case x$0: A @scala.unchecked() =>
66
true
77
case _ =>
88
false
99
})
1010
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
11-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A]
11+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A @scala.unchecked()]
1212
override def productArity: scala.Int = 0
1313
override def productPrefix: java.lang.String = "A"
1414
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleCaseClass-2.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ case class A(x: scala.Int) {
66
scala.runtime.Statics.finalizeHash(acc, 1)
77
}
88
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
9-
case x$0: A =>
9+
case x$0: A @scala.unchecked() =>
1010
this.x.==(x$0.x)
1111
case _ =>
1212
false
1313
})
1414
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
15-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A]
15+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A @scala.unchecked()]
1616
override def productArity: scala.Int = 1
1717
override def productPrefix: java.lang.String = "A"
1818
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleCaseClass-3.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ case class A[T](x: T) {
66
scala.runtime.Statics.finalizeHash(acc, 1)
77
}
88
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
9-
case x$0: A[A.this.T] =>
9+
case x$0: A[A.this.T] @scala.unchecked() =>
1010
this.x.==(x$0.x)
1111
case _ =>
1212
false
1313
})
1414
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
15-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A[A.this.T]]
15+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A[A.this.T] @scala.unchecked()]
1616
override def productArity: scala.Int = 1
1717
override def productPrefix: java.lang.String = "A"
1818
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleCaseObject.decompiled

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package foo {
33
case object Foo {
44
override def hashCode(): scala.Int = 1045991777
55
override def toString(): java.lang.String = "Foo"
6-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[foo.Foo]
6+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[foo.Foo @scala.unchecked()]
77
override def productArity: scala.Int = 0
88
override def productPrefix: java.lang.String = "Foo"
99
override def productElement(n: scala.Int): scala.Any = n match {

0 commit comments

Comments
 (0)