-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
More comprehensive validation of referenced types
This adds more comprehensive validation of types referenced by application types. Specifically, expediter will now report when types referenced via * member declaration * catching exceptions * invokedynamic descriptors * instanceof/cast * arguments or return types of methods invoked on other types * types of fields accessed from other types are missing or have missing supertypes. It will also report issues with array types. The report is compacted to filter out some issues that can be considered duplicates * if application type A references application type B with missing supertype C, issue with A will not be reported * if type A extends a missing type B and also references it (e.g. via a super constructor), the generic "A reference missing type B" will not be reported * if type A refers to a type B whose supertype C is missing, but A also refers to C directly, only the latter will be reported
- Loading branch information
Showing
31 changed files
with
445 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
core/src/main/kotlin/com/toasttab/expediter/parser/SignatureParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package com.toasttab.expediter.parser | ||
|
||
class SignatureParser private constructor(private val signature: String) { | ||
private var idx = 0 | ||
|
||
private fun nextType(internal: Boolean): TypeSignature { | ||
var primitive = true | ||
var dimensions = 0 | ||
var c = signature[idx] | ||
while (c == '[') { | ||
dimensions++ | ||
c = signature[++idx] | ||
} | ||
|
||
val name = if (dimensions > 0 || !internal) { | ||
if (c == 'L') { | ||
primitive = false | ||
val next = signature.indexOf(';', startIndex = idx + 1) | ||
if (next < 0) { | ||
error("error parsing type from $signature, cannot find ';' after index $idx") | ||
} | ||
val start = idx + 1 | ||
idx = next + 1 | ||
signature.substring(start, next) | ||
} else { | ||
signature.substring(idx, ++idx) | ||
} | ||
} else { | ||
signature.substring(idx) | ||
} | ||
|
||
return TypeSignature(name, dimensions, primitive) | ||
} | ||
|
||
private fun parseMethod(): MethodSignature { | ||
if (signature[idx++] != '(') { | ||
error("error parsing $signature, expected to start with '('") | ||
} | ||
|
||
val args = mutableListOf<TypeSignature>() | ||
|
||
while (signature[idx] != ')') { | ||
args.add(nextType(false)) | ||
} | ||
|
||
idx++ | ||
|
||
return MethodSignature(nextType(false), args) | ||
} | ||
|
||
companion object { | ||
/** | ||
* Parses a standard method descriptor, e.g. | ||
* | ||
* (Ljava/lang/Object;)V for void fun(Object) | ||
*/ | ||
fun parseMethod(method: String) = SignatureParser(method).parseMethod() | ||
|
||
/** | ||
* Parses a standard type descriptor, as it appears in a method descriptor, e.g. | ||
* | ||
* L/java/lang/Object; for Object | ||
* [L/java/lang/Object; for Object[] | ||
*/ | ||
fun parseType(type: String) = SignatureParser(type).nextType(false) | ||
|
||
/** | ||
* Parses a internal type descriptor, as reported by ASM for method owners, instanceof, etc; e.g. | ||
* | ||
* [L/java/lang/Object; for Object[] | ||
* | ||
* but just | ||
* | ||
* java/lang/Object for Object | ||
*/ | ||
fun parseInternalType(type: String) = SignatureParser(type).nextType(true) | ||
} | ||
} | ||
|
||
class MethodSignature( | ||
val returnType: TypeSignature, | ||
val argumentTypes: List<TypeSignature> | ||
) { | ||
fun referencedTypes() = (argumentTypes + returnType).filter { !it.primitive }.map { it.scalarName } | ||
} | ||
|
||
class TypeSignature( | ||
val scalarName: String, | ||
val dimensions: Int, | ||
val primitive: Boolean | ||
) { | ||
fun isArray() = dimensions > 0 | ||
fun referencedTypes() = if (primitive) emptySet() else setOf(scalarName) | ||
|
||
fun scalarSignature() = TypeSignature(scalarName, 0, primitive) | ||
val name get() = scalarName + "[]".repeat(dimensions) | ||
} |
Oops, something went wrong.