@@ -2,6 +2,7 @@ package com.typesafe.tools.mima.core
2
2
3
3
import java .util .UUID
4
4
5
+ import scala .annotation .tailrec
5
6
import scala .collection .mutable , mutable .{ ArrayBuffer , ListBuffer }
6
7
7
8
import TastyFormat ._ , NameTags ._ , TastyTagOps ._ , TastyRefs ._
@@ -17,9 +18,8 @@ object TastyUnpickler {
17
18
18
19
def unpickle (in : TastyReader , clazz : ClassInfo , path : String ): Unit = {
19
20
readHeader(in)
20
- val names = readNames(in)
21
- val sectionReaders = readSectionReaders(in ,names)
22
- val tree = sectionReaders.doTrees(unpickleTree)
21
+ val names = readNames(in)
22
+ val tree = unpickleTree(getTreeReader(in, names), names)
23
23
24
24
object trav extends Traverser {
25
25
var pkgNames = List .empty[Name ]
@@ -50,6 +50,15 @@ object TastyUnpickler {
50
50
if (cls != NoClass ) {
51
51
cls._experimental |= clsDef.annots.exists(_.tycon.toString == " scala.annotation.experimental" )
52
52
cls._experimental |= clsDef.annots.exists(_.tycon.toString == " scala.annotation.experimental2" )
53
+
54
+ for (defDef <- clsDef.template.meths) {
55
+ val isExperimental =
56
+ defDef.annots.exists(_.tycon.toString == " scala.annotation.experimental" ) ||
57
+ defDef.annots.exists(_.tycon.toString == " scala.annotation.experimental2" )
58
+ if (isExperimental)
59
+ for (meth <- cls.lookupClassMethods(new MethodInfo (cls, defDef.name.source, 0 , " ()V" )))
60
+ meth._experimental = true
61
+ }
53
62
}
54
63
}
55
64
}
@@ -80,12 +89,47 @@ object TastyUnpickler {
80
89
val tag = readByte()
81
90
82
91
def processLengthTree () = {
83
- val end = readEnd()
84
- def readTrees () = until(end)(readTree()).filter(! _.isInstanceOf [UnknownTree ])
85
- def readPackage () = Pkg (readPath(), readTrees()) // Path Tree* -- package path { topLevelStats }
92
+ def readTrees (end : Addr ) = until(end)(readTree()).filter(! _.isInstanceOf [UnknownTree ])
93
+ def readPackage () = { val end = readEnd(); Pkg (readPath(), readTrees(end)) } // Path Tree* -- package path { topLevelStats }
94
+
95
+ def nothingButMods (end : Addr ) = currentAddr == end || isModifierTag(nextByte)
96
+
97
+ def readDefDef () = {
98
+ // Length NameRef Param* returnType_Term rhs_Term? Modifier* -- modifiers def name [typeparams] paramss : returnType (= rhs)?
99
+ // Param = TypeParam | TermParam
100
+ val end = readEnd()
101
+ val name = readName()
102
+ while (nextByte == TYPEPARAM || nextByte == PARAM || nextByte == EMPTYCLAUSE || nextByte == SPLITCLAUSE ) skipTree(readByte()) // params
103
+ skipTree(readByte()) // returnType
104
+ if (! nothingButMods(end)) skipTree(readByte()) // rhs
105
+ val annots = readAnnotsInMods(end)
106
+ DefDef (name, annots)
107
+ }
108
+
109
+ def readTemplate () = {
110
+ // TypeParam* TermParam* parent_Term* Self? Stat* -- [typeparams] paramss extends parents { self => stats }, where Stat* always starts with the primary constructor.
111
+ // TypeParam = TYPEPARAM Length NameRef type_Term Modifier* -- modifiers name bounds
112
+ // TermParam = PARAM Length NameRef type_Term Modifier* -- modifiers name : type.
113
+ // EMPTYCLAUSE -- an empty parameter clause ()
114
+ // SPLITCLAUSE -- splits two non-empty parameter clauses of the same kind
115
+ // Self = SELFDEF selfName_NameRef selfType_Term -- selfName : selfType
116
+ assert(readByte() == TEMPLATE )
117
+ val end = readEnd()
118
+ while (nextByte == TYPEPARAM ) skipTree(readByte()) // vparams
119
+ while (nextByte == PARAM || nextByte == EMPTYCLAUSE || nextByte == SPLITCLAUSE ) skipTree(readByte()) // tparams
120
+ while (nextByte != SELFDEF && nextByte != DEFDEF ) skipTree(readByte()) // parents
121
+ if (nextByte == SELFDEF ) skipTree(readByte()) // self
122
+ val meths = new ListBuffer [DefDef ]
123
+ doUntil(end)(readByte match {
124
+ case DEFDEF => meths += readDefDef()
125
+ case tag => skipTree(tag)
126
+ })
127
+ Template (meths.toList)
128
+ }
129
+
130
+ def readClassDef (name : Name , end : Addr ) = ClsDef (name.toTypeName, readTemplate(), readAnnotsInMods(end)) // NameRef Template Modifier* -- modifiers class name template
86
131
87
- def readClassDef (name : TypeName ) = ClsDef (name, readAnnotsInMods(end)) // NameRef Template Modifier* -- modifiers class name template
88
- def readTypeDefAlt () = UnknownTree (TYPEDEF ) // NameRef type_Term Modifier* -- modifiers type name (= type | bounds) | modifiers class name template
132
+ def readTypeMemberDef (end : Addr ) = { goto(end); UnknownTree (TYPEDEF ) } // NameRef type_Term Modifier* -- modifiers type name (= type | bounds)
89
133
90
134
def readAnnotsInMods (end : Addr ) = {
91
135
val annots = new ListBuffer [Annot ]
@@ -98,14 +142,16 @@ object TastyUnpickler {
98
142
}
99
143
100
144
def readTypeDef () = {
101
- val name = readName().toTypeName
102
- if (skipTree(readByte()).tag == TEMPLATE ) readClassDef(name) else readTypeDefAlt()
145
+ val end = readEnd()
146
+ val name = readName()
147
+ if (nextByte == TEMPLATE ) readClassDef(name, end) else readTypeMemberDef(end)
103
148
}
104
149
150
+ val end = fork.readEnd()
105
151
val tree = tag match {
106
152
case PACKAGE => readPackage()
107
153
case TYPEDEF => readTypeDef()
108
- case _ => goto(end); UnknownTree (tag)
154
+ case _ => skipTree (tag)
109
155
}
110
156
softAssertEnd(end, s " start= $start tag= ${astTagToString(tag)}" )
111
157
tree
@@ -150,7 +196,9 @@ object TastyUnpickler {
150
196
151
197
final case class Pkg (path : Path , trees : List [Tree ]) extends Tree { def show = s " package $path${trees.map(" \n " + _).mkString}" }
152
198
153
- final case class ClsDef (name : Name , annots : List [Annot ] = Nil ) extends Tree { def show = s " ${annots.map(" " + _ + " " ).mkString}class $name" }
199
+ final case class ClsDef (name : TypeName , template : Template , annots : List [Annot ]) extends Tree { def show = s " ${annots.map(" " + _ + " " ).mkString}class $name$template" }
200
+ final case class Template (meths : List [DefDef ]) extends Tree { def show = s " ${meths.map(" \n " + _).mkString}" }
201
+ final case class DefDef (name : Name , annots : List [Annot ] = Nil ) extends Tree { def show = s " ${annots.map(" " + _ + " " ).mkString} def $name" }
154
202
155
203
sealed trait Type extends Tree
156
204
final case class UnknownType (tag : Int ) extends Type { def show = s " UnknownType( ${astTagToString(tag)}) " }
@@ -166,6 +214,8 @@ object TastyUnpickler {
166
214
def traverse (tree : Tree ): Unit = tree match {
167
215
case pkg : Pkg => traversePkg(pkg)
168
216
case clsDef : ClsDef => traverseClsDef(clsDef)
217
+ case tmpl : Template => traverseTemplate(tmpl)
218
+ case defDef : DefDef => traverseDefDef(defDef)
169
219
case tp : Type => traverseType(tp)
170
220
case annot : Annot => traverseAnnot(annot)
171
221
case UnknownTree (_) =>
@@ -178,6 +228,8 @@ object TastyUnpickler {
178
228
179
229
def traversePkg (pkg : Pkg ) = { traverse(pkg.path); traverseTrees(pkg.trees) }
180
230
def traverseClsDef (clsDef : ClsDef ) = { traverseName(clsDef.name); traverseAnnots(clsDef.annots) }
231
+ def traverseTemplate (tmpl : Template ) = { traverseTrees(tmpl.meths) }
232
+ def traverseDefDef (defDef : DefDef ) = { traverseName(defDef.name); traverseAnnots(defDef.annots) }
181
233
def traverseAnnot (annot : Annot ) = { traverse(annot.tycon); traverse(annot.fullAnnotation) }
182
234
183
235
def traversePath (path : Path ) = path match {
@@ -206,25 +258,26 @@ object TastyUnpickler {
206
258
override def traverse (tree : Tree ): Unit = { pf.runWith(results += _)(tree); super .traverse(tree) }
207
259
}
208
260
209
- def readSectionReaders (in : TastyReader , names : Names ): SectionReaders = {
210
- val readers = new mutable.HashMap [Name , TastyReader ]
211
- while (! in.isAtEnd) {
212
- val name = names(in.readNat())
213
- val end = in.readEnd()
214
- val curr = in.currentAddr.index
215
- in.goto(end)
216
- readers(name) = new TastyReader (in.bytes, curr, end.index, curr)
217
- }
218
- new SectionReaders (readers.toMap, names)
261
+ def getTreeReader (in : TastyReader , names : Names ): TastyReader = {
262
+ getSectionReader(in, names, ASTsSection ).getOrElse(sys.error(s " No $ASTsSection section?! " ))
219
263
}
220
264
221
- final class SectionReaders (readers : Map [Name , TastyReader ], names : Names ) {
222
- def doTrees [R ](f : (TastyReader , Names ) => R ) = f(readers(SimpleName (ASTsSection )), names)
223
- def unpickle [R ](sec : SectionUnpickler [R ]) = readers.get(sec.name).map(sec.unpickle(_, names))
265
+ def getSectionReader (in : TastyReader , names : Names , name : String ): Option [TastyReader ] = {
266
+ import in ._
267
+ @ tailrec def loop (): Option [TastyReader ] = {
268
+ if (isAtEnd) None
269
+ else if (names(readNat()).debug == name) Some (nextSectionReader(in))
270
+ else { goto(readEnd()); loop() }
271
+ }
272
+ loop()
224
273
}
225
274
226
- abstract class SectionUnpickler [R ](val name : Name ) {
227
- def unpickle (reader : TastyReader , names : Names ): R
275
+ private def nextSectionReader (in : TastyReader ) = {
276
+ import in ._
277
+ val end = readEnd()
278
+ val curr = currentAddr
279
+ goto(end)
280
+ new TastyReader (bytes, curr.index, end.index, curr.index)
228
281
}
229
282
230
283
def readNames (in : TastyReader ): Names = {
@@ -443,9 +496,8 @@ object TastyUnpickler {
443
496
444
497
def doClassNames (in : TastyReader , path : String ): Unit = {
445
498
readHeader(in)
446
- val names = readNames(in)
447
- val sectionReaders = readSectionReaders(in, names)
448
- val (pkg, nme) = sectionReaders.doTrees(unpicklePkgAndClsName)
499
+ val names = readNames(in)
500
+ val (pkg, nme) = unpicklePkgAndClsName(getTreeReader(in, names), names)
449
501
println(s " $path -> ${pkg.source}. ${nme.source}" )
450
502
}
451
503
0 commit comments