Skip to content

Commit

Permalink
Protobuf schema for type descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
ogolberg committed Oct 28, 2023
1 parent 756daa0 commit 446ad7d
Show file tree
Hide file tree
Showing 24 changed files with 271 additions and 215 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@

package com.toasttab.expediter.sniffer

import com.toasttab.expediter.types.AccessDeclaration
import com.toasttab.expediter.types.AccessProtection
import com.toasttab.expediter.types.MemberDescriptor
import com.toasttab.expediter.types.MemberSymbolicReference
import com.toasttab.expediter.types.TypeDescriptor
import com.toasttab.expediter.types.TypeExtensibility
import com.toasttab.expediter.types.TypeFlavor
import protokt.v1.toasttab.expediter.v1.AccessDeclaration
import protokt.v1.toasttab.expediter.v1.AccessProtection
import protokt.v1.toasttab.expediter.v1.MemberDescriptor
import protokt.v1.toasttab.expediter.v1.SymbolicReference
import protokt.v1.toasttab.expediter.v1.TypeDescriptor
import protokt.v1.toasttab.expediter.v1.TypeExtensibility
import protokt.v1.toasttab.expediter.v1.TypeFlavor
import java.io.InputStream
import java.util.zip.GZIPInputStream

Expand All @@ -31,40 +31,48 @@ import java.util.zip.GZIPInputStream
object AnimalSnifferParser {
fun parse(stream: InputStream): List<TypeDescriptor> {
return Deserializer(GZIPInputStream(stream)).deserialize().map {
val members = it.signatures.map { sig ->
val fields = mutableListOf<MemberDescriptor>()
val methods = mutableListOf<MemberDescriptor>()

for (sig in it.signatures) {
val fieldIdx = sig.indexOf('#')

if (fieldIdx >= 0) {
MemberDescriptor(
MemberSymbolicReference.FieldSymbolicReference(
sig.substring(0, fieldIdx),
sig.substring(fieldIdx + 1)
),
AccessDeclaration.UNKNOWN,
AccessProtection.UNKNOWN
fields.add(
MemberDescriptor {
ref = SymbolicReference {
name = sig.substring(0, fieldIdx)
signature = sig.substring(fieldIdx + 1)
}
declaration = AccessDeclaration.UNKNOWN
protection = AccessProtection.UNKNOWN
}
)
} else {
val methodIdx = sig.indexOf('(')
MemberDescriptor(
MemberSymbolicReference.MethodSymbolicReference(
sig.substring(0, methodIdx),
sig.substring(methodIdx)
),
AccessDeclaration.UNKNOWN,
AccessProtection.UNKNOWN
methods.add(
MemberDescriptor {
ref = SymbolicReference {
name = sig.substring(0, methodIdx)
signature = sig.substring(methodIdx)
}
declaration = AccessDeclaration.UNKNOWN
protection = AccessProtection.UNKNOWN
}
)
}
}

TypeDescriptor(
it.name,
it.superClass,
it.superInterfaces,
members,
AccessProtection.UNKNOWN,
TypeFlavor.UNKNOWN,
TypeExtensibility.UNKNOWN
)
TypeDescriptor {
name = it.name
superName = it.superClass
interfaces = it.superInterfaces
this.fields = fields
this.methods = methods
protection = AccessProtection.UNKNOWN
flavor = TypeFlavor.UNKNOWN
extensibility = TypeExtensibility.UNKNOWN
}
}
}
}
9 changes: 4 additions & 5 deletions core/src/main/kotlin/com/toasttab/expediter/AccessCheck.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.toasttab.expediter

import com.toasttab.expediter.types.AccessProtection
import com.toasttab.expediter.types.ApplicationTypeWithResolvedHierarchy
import com.toasttab.expediter.types.MemberDescriptor
import com.toasttab.expediter.types.MemberType
import com.toasttab.expediter.types.ResolvedTypeHierarchy
import com.toasttab.expediter.types.TypeDescriptor
import protokt.v1.toasttab.expediter.v1.AccessProtection
import protokt.v1.toasttab.expediter.v1.MemberDescriptor
import protokt.v1.toasttab.expediter.v1.TypeDescriptor

object AccessCheck {
fun <M : MemberType> allowedAccess(caller: ApplicationTypeWithResolvedHierarchy, target: TypeDescriptor, member: MemberDescriptor<M>): Boolean {
fun allowedAccess(caller: ApplicationTypeWithResolvedHierarchy, target: TypeDescriptor, member: MemberDescriptor): Boolean {
return if (member.protection == AccessProtection.PRIVATE) {
caller.name == target.name
} else if (member.protection == AccessProtection.PACKAGE_PRIVATE || target.protection == AccessProtection.PACKAGE_PRIVATE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

package com.toasttab.expediter

import com.toasttab.expediter.types.AccessDeclaration
import com.toasttab.expediter.types.AccessProtection
import com.toasttab.expediter.types.TypeExtensibility
import com.toasttab.expediter.types.TypeFlavor
import org.objectweb.asm.Opcodes
import protokt.v1.toasttab.expediter.v1.AccessDeclaration
import protokt.v1.toasttab.expediter.v1.AccessProtection
import protokt.v1.toasttab.expediter.v1.TypeExtensibility
import protokt.v1.toasttab.expediter.v1.TypeFlavor

object AttributeParser {
fun flavor(access: Int) = if (access and Opcodes.ACC_INTERFACE != 0) TypeFlavor.INTERFACE else TypeFlavor.CLASS
Expand Down
21 changes: 11 additions & 10 deletions core/src/main/kotlin/com/toasttab/expediter/Expediter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ package com.toasttab.expediter

import com.toasttab.expediter.ignore.Ignore
import com.toasttab.expediter.issue.Issue
import com.toasttab.expediter.types.AccessDeclaration
import com.toasttab.expediter.types.ApplicationTypeWithResolvedHierarchy
import com.toasttab.expediter.types.InspectedTypes
import com.toasttab.expediter.types.MemberAccess
import com.toasttab.expediter.types.MemberDescriptor
import com.toasttab.expediter.types.MemberType
import com.toasttab.expediter.types.MethodAccessType
import com.toasttab.expediter.types.OptionalResolvedTypeHierarchy
import com.toasttab.expediter.types.PlatformTypeProvider
import com.toasttab.expediter.types.ResolvedTypeHierarchy
import com.toasttab.expediter.types.TypeDescriptor
import com.toasttab.expediter.types.TypeExtensibility
import com.toasttab.expediter.types.TypeFlavor
import com.toasttab.expediter.types.members
import protokt.v1.toasttab.expediter.v1.AccessDeclaration
import protokt.v1.toasttab.expediter.v1.MemberDescriptor
import protokt.v1.toasttab.expediter.v1.TypeDescriptor
import protokt.v1.toasttab.expediter.v1.TypeExtensibility
import protokt.v1.toasttab.expediter.v1.TypeFlavor

class Expediter(
private val ignore: Ignore,
Expand Down Expand Up @@ -121,8 +122,8 @@ fun <M : MemberType> findIssue(type: ApplicationTypeWithResolvedHierarchy, acces
}
}
}
private class MemberWithDeclaringType<M : MemberType> (
val member: MemberDescriptor<M>,
private class MemberWithDeclaringType(
val member: MemberDescriptor,
val declaringType: TypeDescriptor
)

Expand All @@ -144,11 +145,11 @@ private fun <M : MemberType> ResolvedTypeHierarchy.CompleteTypeHierarchy.filterT
}
}

private fun <M : MemberType> ResolvedTypeHierarchy.CompleteTypeHierarchy.resolveMember(access: MemberAccess<M>): MemberWithDeclaringType<M>? {
private fun <M : MemberType> ResolvedTypeHierarchy.CompleteTypeHierarchy.resolveMember(access: MemberAccess<M>): MemberWithDeclaringType? {
for (cls in filterToAccessType(access)) {
for (m in cls.members) {
if (access.ref == m.ref) {
return MemberWithDeclaringType(m as MemberDescriptor<M>, cls)
if (access.ref.same(m.ref!!)) {
return MemberWithDeclaringType(m, cls)
}
}
}
Expand Down
70 changes: 38 additions & 32 deletions core/src/main/kotlin/com/toasttab/expediter/TypeParsers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@ package com.toasttab.expediter
import com.toasttab.expediter.types.ApplicationType
import com.toasttab.expediter.types.FieldAccessType
import com.toasttab.expediter.types.MemberAccess
import com.toasttab.expediter.types.MemberDescriptor
import com.toasttab.expediter.types.MemberSymbolicReference
import com.toasttab.expediter.types.MethodAccessType
import com.toasttab.expediter.types.TypeDescriptor
import com.toasttab.expediter.types.TypeExtensibility
import com.toasttab.expediter.types.TypeFlavor
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassReader.SKIP_DEBUG
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.FieldVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Opcodes.ASM9
import protokt.v1.toasttab.expediter.v1.MemberDescriptor
import protokt.v1.toasttab.expediter.v1.SymbolicReference
import protokt.v1.toasttab.expediter.v1.TypeDescriptor
import java.io.InputStream

object TypeParsers {
Expand Down Expand Up @@ -77,7 +76,7 @@ private class ApplicationTypeParser(private val source: String) : ClassVisitor(A
MemberAccess.MethodAccess(
owner,
null,
MemberSymbolicReference.MethodSymbolicReference(name, descriptor),
MemberSymbolicReference(name, descriptor),
invokeType
)
)
Expand All @@ -94,7 +93,7 @@ private class ApplicationTypeParser(private val source: String) : ClassVisitor(A
MemberAccess.FieldAccess(
owner,
null,
MemberSymbolicReference.FieldSymbolicReference(name, descriptor),
MemberSymbolicReference(name, descriptor),
type
)
)
Expand All @@ -104,15 +103,16 @@ private class ApplicationTypeParser(private val source: String) : ClassVisitor(A
}

private class TypeDescriptorParser : ClassVisitor(ASM9) {
private var name: String? = null
private var superName: String? = null
private val interfaces: MutableList<String> = arrayListOf()
private val members: MutableList<MemberDescriptor<*>> = mutableListOf()
private var access: Int = 0
private var typeFlavor: TypeFlavor = TypeFlavor.UNKNOWN
private var typeExtensibility: TypeExtensibility = TypeExtensibility.UNKNOWN
private val builder = TypeDescriptor.Builder()
private val methods = mutableListOf<MemberDescriptor>()
private val fields = mutableListOf<MemberDescriptor>()

fun get() = TypeDescriptor(name!!, superName, interfaces, members, AttributeParser.protection(access), typeFlavor, typeExtensibility)
fun get(): TypeDescriptor {
builder.methods = methods
builder.fields = fields

return builder.build()
}

override fun visit(
version: Int,
Expand All @@ -122,12 +122,12 @@ private class TypeDescriptorParser : ClassVisitor(ASM9) {
superName: String?,
interfaces: Array<out String>
) {
this.name = name
this.superName = superName
this.access = access
this.typeFlavor = AttributeParser.flavor(access)
this.typeExtensibility = AttributeParser.extensibility(access)
this.interfaces.addAll(interfaces)
builder.name = name
builder.superName = superName
builder.flavor = AttributeParser.flavor(access)
builder.extensibility = AttributeParser.extensibility(access)
builder.protection = AttributeParser.protection(access)
builder.interfaces = interfaces.toList()
}

override fun visitMethod(
Expand All @@ -137,12 +137,15 @@ private class TypeDescriptorParser : ClassVisitor(ASM9) {
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
members.add(
MemberDescriptor(
MemberSymbolicReference.MethodSymbolicReference(name, descriptor),
AttributeParser.declaration(access),
AttributeParser.protection(access)
)
methods.add(
MemberDescriptor {
ref = SymbolicReference {
this.name = name
this.signature = descriptor
}
declaration = AttributeParser.declaration(access)
protection = AttributeParser.protection(access)
}
)

return null
Expand All @@ -155,12 +158,15 @@ private class TypeDescriptorParser : ClassVisitor(ASM9) {
signature: String?,
value: Any?
): FieldVisitor? {
members.add(
MemberDescriptor(
MemberSymbolicReference.FieldSymbolicReference(name, descriptor),
AttributeParser.declaration(access),
AttributeParser.protection(access)
)
fields.add(
MemberDescriptor {
ref = SymbolicReference {
this.name = name
this.signature = descriptor
}
declaration = AttributeParser.declaration(access)
protection = AttributeParser.protection(access)
}
)

return null
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/kotlin/com/toasttab/expediter/ignore/Ignore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package com.toasttab.expediter.ignore

import com.toasttab.expediter.issue.Issue
import com.toasttab.expediter.types.MemberSymbolicReference
import java.io.Serializable

interface Ignore : Serializable {
Expand Down Expand Up @@ -48,7 +47,7 @@ interface Ignore : Serializable {

object IsConstructor : Ignore {
override fun ignore(issue: Issue) = issue is Issue.WithMemberAccess && issue.member.ref.run {
this is MemberSymbolicReference.MethodSymbolicReference && isConstructor()
isConstructor()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

package com.toasttab.expediter.types

import protokt.v1.toasttab.expediter.v1.TypeDescriptor

class InMemoryPlatformTypeProvider private constructor(
private val types: Map<String, TypeDescriptor>
) : PlatformTypeProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
package com.toasttab.expediter.types

import com.toasttab.expediter.issue.Issue
import protokt.v1.toasttab.expediter.v1.AccessProtection
import protokt.v1.toasttab.expediter.v1.TypeDescriptor
import protokt.v1.toasttab.expediter.v1.TypeExtensibility
import protokt.v1.toasttab.expediter.v1.TypeFlavor
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap

Expand Down Expand Up @@ -66,7 +70,13 @@ class InspectedTypes private constructor(
return inspectedCache[s] ?: inspectedCache.computeIfAbsent(s) { s ->
if (s.startsWith("[")) {
// TODO: make up a type descriptor for an array type; we could validate that the element type actually exists
TypeDescriptor(s, "java/lang/Object", emptyList(), emptyList(), AccessProtection.UNKNOWN, TypeFlavor.CLASS, TypeExtensibility.FINAL)
TypeDescriptor {
name = s
superName = "java/lang/Object"
protection = AccessProtection.UNKNOWN
flavor = TypeFlavor.CLASS
extensibility = TypeExtensibility.FINAL
}
} else {
platformTypeProvider.lookupPlatformType(s)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.toasttab.expediter.types

import com.toasttab.expediter.TypeParsers
import protokt.v1.toasttab.expediter.v1.TypeDescriptor
import java.nio.file.Paths
import java.util.jar.JarFile
import kotlin.io.path.pathString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

package com.toasttab.expediter.types

import protokt.v1.toasttab.expediter.v1.TypeDescriptor

interface PlatformTypeProvider {
fun lookupPlatformType(name: String): TypeDescriptor?
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
*/

package com.toasttab.expediter.types

import protokt.v1.toasttab.expediter.v1.TypeDescriptor

class TypeHierarchy(
val type: TypeDescriptor,
val superTypes: Set<OptionalType>
Expand Down
Loading

0 comments on commit 446ad7d

Please sign in to comment.