diff --git a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileParser.scala b/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileParser.scala index 3a132098..a463413d 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileParser.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileParser.scala @@ -215,8 +215,8 @@ private[reader] object ClassfileParser { allRegisteredSymbols += sym sym - def loadMembers(): IArray[(TermSymbol, AccessFlags, SigOrDesc)] = - val buf = IArray.newBuilder[(TermSymbol, AccessFlags, SigOrDesc)] + def loadMembers(): IArray[(TermSymbol, AccessFlags, MemberSig)] = + val buf = IArray.newBuilder[(TermSymbol, AccessFlags, MemberSig)] structure.fields.use { reader.readFields { (name, sigOrDesc, access) => buf += ((createMember(name, EmptyFlagSet, access), access, sigOrDesc)) @@ -242,7 +242,7 @@ private[reader] object ClassfileParser { structure.supers.use { val superClass = reader.readSuperClass().map(binaryName) val interfaces = reader.readInterfaces().map(binaryName) - Descriptors.parseSupers(cls, superClass, interfaces) + JavaSignatures.parseSupers(cls, superClass, interfaces) } end parents val parents1 = @@ -262,10 +262,8 @@ private[reader] object ClassfileParser { else if cls.isString then rctx.createStringMagicMethods(cls) else if cls.isJavaEnum then rctx.createEnumMagicMethods(cls) - for (sym, javaFlags, sigOrDesc) <- loadMembers() do - val parsedType = sigOrDesc match - case SigOrDesc.Desc(desc) => Descriptors.parseDescriptor(sym, desc) - case SigOrDesc.Sig(sig) => JavaSignatures.parseSignature(sym, sig, allRegisteredSymbols) + for (sym, javaFlags, memberSig) <- loadMembers() do + val parsedType = JavaSignatures.parseSignature(sym, memberSig, allRegisteredSymbols) val adaptedType = if sym.isMethod && sym.name == nme.Constructor then cls.makePolyConstructorType(parsedType) else if sym.isMethod && javaFlags.isVarargsIfMethod then patchForVarargs(sym, parsedType) diff --git a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileReader.scala b/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileReader.scala index 73af55fb..03aae987 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileReader.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/ClassfileReader.scala @@ -187,15 +187,15 @@ private[classfiles] final class ClassfileReader private () { reader } - def readFields(op: (SimpleName, SigOrDesc, AccessFlags) => Unit)(using DataStream, ConstantPool): Unit = + def readFields(op: (SimpleName, MemberSig, AccessFlags) => Unit)(using DataStream, ConstantPool): Unit = readMembers(isMethod = false, op) - def readMethods(op: (SimpleName, SigOrDesc, AccessFlags) => Unit)(using DataStream, ConstantPool): Unit = + def readMethods(op: (SimpleName, MemberSig, AccessFlags) => Unit)(using DataStream, ConstantPool): Unit = readMembers(isMethod = true, op) private def readMembers( isMethod: Boolean, - op: (SimpleName, SigOrDesc, AccessFlags) => Unit + op: (SimpleName, MemberSig, AccessFlags) => Unit )(using ds: DataStream, pool: ConstantPool): Unit = { val count = data.readU2() loop(count) { @@ -214,9 +214,7 @@ private[classfiles] final class ClassfileReader private () { case _ => false } val sig = sigOrNull - if !accessFlags.isSynthetic then - if sig == null then op(name, SigOrDesc.Desc(desc), accessFlags) - else op(name, SigOrDesc.Sig(sig), accessFlags) + if !accessFlags.isSynthetic then op(name, if sig == null then desc else sig, accessFlags) } } @@ -399,9 +397,7 @@ private[classfiles] object ClassfileReader { IArray.unsafeFromArray(arr) } - enum SigOrDesc: - case Sig(str: String) - case Desc(str: String) + type MemberSig = String enum SigOrSupers: case Sig(str: String) diff --git a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/Descriptors.scala b/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/Descriptors.scala deleted file mode 100644 index 1fdcaa23..00000000 --- a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/Descriptors.scala +++ /dev/null @@ -1,125 +0,0 @@ -package tastyquery.reader.classfiles - -import scala.annotation.switch - -import tastyquery.Contexts.* -import tastyquery.Exceptions.* -import tastyquery.Names.* -import tastyquery.Types.* -import tastyquery.Symbols.* -import tastyquery.Flags - -import tastyquery.reader.ReaderContext -import tastyquery.reader.ReaderContext.rctx - -import ClassfileParser.* - -private[classfiles] object Descriptors: - - def parseSupers(cls: ClassSymbol, superClass: Option[SimpleName], interfaces: IArray[SimpleName])( - using ReaderContext, - InnerClasses, - Resolver - ): List[Type] = - cls.withTypeParams(Nil) - if cls.isObject then rctx.AnyType :: rctx.MatchableType :: Nil - else - val superRef = superClass.map(classRef).getOrElse(rctx.ObjectType) - superRef :: interfaces.map(classRef).toList - - def classRef(binaryName: SimpleName)(using ReaderContext, InnerClasses, Resolver): TypeRef = - resolver.resolve(binaryName) - - @throws[ClassfileFormatException] - def parseDescriptor(member: Symbol, desc: String)(using ReaderContext, InnerClasses, Resolver): TypeOrMethodic = - // TODO: once we support inner classes, decide if we merge with parseSignature - var offset = 0 - var end = desc.length - val isMethod = member.isTerm && member.asTerm.isMethod - - def available = end - offset - - def peek = desc.charAt(offset) - - def consume(char: Char): Boolean = - if available >= 1 && peek == char then - offset += 1 - true - else false - - def charsUntil(char: Char): String = - val old = offset - while available > 0 && peek != char do offset += 1 - if available == 0 then abort - else - val result = desc.slice(old, offset) - offset += 1 // skip char - result - - def commitSimple[T](len: Int, t: T): T = - offset += len - t - - def baseType: Option[Type] = - if available >= 1 then - (peek: @switch) match - case 'B' => commitSimple(1, Some(rctx.ByteType)) - case 'C' => commitSimple(1, Some(rctx.CharType)) - case 'D' => commitSimple(1, Some(rctx.DoubleType)) - case 'F' => commitSimple(1, Some(rctx.FloatType)) - case 'I' => commitSimple(1, Some(rctx.IntType)) - case 'J' => commitSimple(1, Some(rctx.LongType)) - case 'S' => commitSimple(1, Some(rctx.ShortType)) - case 'Z' => commitSimple(1, Some(rctx.BooleanType)) - case _ => None - else None - - def objectType: Option[Type] = - if consume('L') then // has 'L', ';', and class name - val binaryName = termName(charsUntil(';')) // consume until ';', skip ';' - Some(classRef(binaryName)) - else None - - def arrayType: Option[Type] = - if consume('[') then - val tpe = fieldDescriptor - Some(rctx.ArrayTypeOf(tpe)) - else None - - def fieldDescriptor: Type = - baseType.orElse(objectType).orElse(arrayType).getOrElse(abort) - - def returnDescriptor: Type = - if consume('V') then rctx.UnitType - else fieldDescriptor - - def methodDescriptor: MethodType = - if consume('(') then // must have '(', ')', and return type - def paramDescriptors(acc: List[Type]): List[Type] = - if consume(')') then acc.reverse - else paramDescriptors(fieldDescriptor :: acc) - val params = paramDescriptors(Nil) - val ret = returnDescriptor - MethodType((0 until params.size).map(i => termName(s"x$$$i")).toList, params, ret) - else abort - - def unconsumed: Nothing = - throw ClassfileFormatException( - s"Expected end of descriptor but found $"${desc.slice(offset, end)}$", [is method? $isMethod]" - ) - - def abort: Nothing = - val msg = - if available == 0 then "Unexpected end of descriptor" - else s"Unexpected characted '$peek' in descriptor" - throw ClassfileFormatException(s"$msg of $member, original: `$desc` [is method? $isMethod]") - - val parsedDescriptor = - if isMethod then methodDescriptor - else fieldDescriptor - - if available > 0 then unconsumed - - parsedDescriptor - end parseDescriptor -end Descriptors diff --git a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/JavaSignatures.scala b/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/JavaSignatures.scala index c4f3b7f4..5a4d8f2f 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/JavaSignatures.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/reader/classfiles/JavaSignatures.scala @@ -15,7 +15,7 @@ import tastyquery.Symbols.* import tastyquery.reader.ReaderContext import tastyquery.reader.ReaderContext.rctx -import ClassfileParser.{InnerClasses, Resolver} +import ClassfileParser.{InnerClasses, Resolver, resolver} private[classfiles] object JavaSignatures: @@ -23,6 +23,21 @@ private[classfiles] object JavaSignatures: private type JavaSignature = Null | PolyType | Map[TypeName, ClassTypeParamSymbol] | IgnoreTParamRefs.type + private def classRef(binaryName: SimpleName)(using ReaderContext, InnerClasses, Resolver): TypeRef = + resolver.resolve(binaryName) + + def parseSupers(cls: ClassSymbol, superClass: Option[SimpleName], interfaces: IArray[SimpleName])( + using ReaderContext, + InnerClasses, + Resolver + ): List[Type] = + cls.withTypeParams(Nil) + if cls.isObject then rctx.AnyType :: rctx.MatchableType :: Nil + else + val superRef = superClass.map(classRef).getOrElse(rctx.ObjectType) + superRef :: interfaces.map(classRef).toList + end parseSupers + @throws[ClassfileFormatException] def parseSignature(member: Symbol { val owner: Symbol }, signature: String, allRegisteredSymbols: Growable[Symbol])( using ReaderContext, @@ -163,7 +178,7 @@ private[classfiles] object JavaSignatures: end classTypeSignatureRest if consume('L') then // must have 'L', identifier, and ';'. - val pre = simpleClassTypeSignature(Descriptors.classRef(binaryName())) + val pre = simpleClassTypeSignature(classRef(binaryName())) Some(classTypeSignatureRest(pre)) else None end classTypeSignature @@ -279,7 +294,7 @@ private[classfiles] object JavaSignatures: classRest(null) def fieldSignature: Type = - referenceType(null) + baseType.getOrElse(referenceType(null)) def cookFailure(tname: TypeName, reason: String): Nothing = val path = if !isClass then s"${member.owner.displayFullName}#${member.name}" else member.displayFullName