mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2024-11-10 01:02:22 +01:00
feat: Retrieve annotations in super and interface classes
This commit is contained in:
parent
f1de9b39ef
commit
7aeae93f3d
5 changed files with 106 additions and 29 deletions
|
@ -1,35 +1,61 @@
|
|||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package app.revanced.patcher.extensions
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal object AnnotationExtensions {
|
||||
/**
|
||||
* Search for an annotation recursively.
|
||||
*
|
||||
* @param targetAnnotationClass The annotation class to search for.
|
||||
* @param searchedClasses A set of annotations that have already been searched.
|
||||
* @return The annotation if found, otherwise null.
|
||||
*/
|
||||
fun <T : Annotation> Class<*>.findAnnotationRecursively(
|
||||
targetAnnotationClass: Class<T>,
|
||||
searchedClasses: HashSet<Annotation> = hashSetOf(),
|
||||
): T? {
|
||||
annotations.forEach { annotation ->
|
||||
// Terminate if the annotation is already searched.
|
||||
if (annotation in searchedClasses) return@forEach
|
||||
searchedClasses.add(annotation)
|
||||
|
||||
// Terminate if the annotation is found.
|
||||
if (targetAnnotationClass == annotation.annotationClass.java) return annotation as T
|
||||
|
||||
return annotation.annotationClass.java.findAnnotationRecursively(
|
||||
targetAnnotationClass,
|
||||
searchedClasses,
|
||||
) ?: return@forEach
|
||||
}
|
||||
|
||||
// Search the super class.
|
||||
superclass?.findAnnotationRecursively(
|
||||
targetAnnotationClass,
|
||||
searchedClasses,
|
||||
)?.let { return it }
|
||||
|
||||
// Search the interfaces.
|
||||
interfaces.forEach { superClass ->
|
||||
return superClass.findAnnotationRecursively(
|
||||
targetAnnotationClass,
|
||||
searchedClasses,
|
||||
) ?: return@forEach
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for an annotation recursively.
|
||||
*
|
||||
* First the annotations, then the annotated classes super class and then it's interfaces
|
||||
* are searched for the annotation recursively.
|
||||
*
|
||||
* @param targetAnnotation The annotation to search for.
|
||||
* @return The annotation if found, otherwise null.
|
||||
*/
|
||||
fun <T : Annotation> Class<*>.findAnnotationRecursively(targetAnnotation: Class<T>): T? {
|
||||
fun <T : Annotation> Class<*>.findAnnotationRecursively(
|
||||
targetAnnotation: Class<T>,
|
||||
searchedAnnotations: HashSet<Annotation>,
|
||||
): T? {
|
||||
val found = this.annotations.firstOrNull { it.annotationClass.java.name == targetAnnotation.name }
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
if (found != null) return found as T
|
||||
|
||||
for (annotation in this.annotations) {
|
||||
if (searchedAnnotations.contains(annotation)) continue
|
||||
searchedAnnotations.add(annotation)
|
||||
|
||||
return annotation.annotationClass.java.findAnnotationRecursively(
|
||||
targetAnnotation,
|
||||
searchedAnnotations
|
||||
) ?: continue
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return this.findAnnotationRecursively(targetAnnotation, hashSetOf())
|
||||
}
|
||||
fun <T : Annotation> KClass<*>.findAnnotationRecursively(targetAnnotation: KClass<T>) =
|
||||
java.findAnnotationRecursively(targetAnnotation.java)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ object MethodFingerprintExtensions {
|
|||
*/
|
||||
@Deprecated(
|
||||
message = "Use the property instead.",
|
||||
replaceWith = ReplaceWith("this.fuzzyPatternScanMethod")
|
||||
replaceWith = ReplaceWith("this.fuzzyPatternScanMethod"),
|
||||
)
|
||||
val MethodFingerprint.fuzzyPatternScanMethod
|
||||
get() = this.fuzzyPatternScanMethod
|
||||
|
|
|
@ -48,7 +48,7 @@ abstract class MethodFingerprint(
|
|||
*
|
||||
* If the annotation is not present, this property is null.
|
||||
*/
|
||||
val fuzzyPatternScanMethod = javaClass.findAnnotationRecursively(FuzzyPatternScanMethod::class.java)
|
||||
val fuzzyPatternScanMethod = this::class.findAnnotationRecursively(FuzzyPatternScanMethod::class)
|
||||
|
||||
/**
|
||||
* Resolve a [MethodFingerprint] using the lookup map built by [initializeLookupMaps].
|
||||
|
|
|
@ -5,9 +5,10 @@ package app.revanced.patcher.patch
|
|||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.data.Context
|
||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||
import app.revanced.patcher.patch.options.PatchOptions
|
||||
import java.io.Closeable
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import app.revanced.patcher.patch.annotation.Patch as PatchAnnotation
|
||||
|
||||
/**
|
||||
* A ReVanced patch.
|
||||
|
@ -60,7 +61,7 @@ sealed class Patch<out T : Context<*>> {
|
|||
val options = PatchOptions()
|
||||
|
||||
init {
|
||||
this::class.findAnnotation<app.revanced.patcher.patch.annotation.Patch>()?.let { annotation ->
|
||||
this::class.findAnnotationRecursively(PatchAnnotation::class)?.let { annotation ->
|
||||
name = annotation.name.ifEmpty { null }
|
||||
description = annotation.description.ifEmpty { null }
|
||||
compatiblePackages =
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package app.revanced.patcher.extensions
|
||||
|
||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
private object AnnotationExtensionsTest {
|
||||
@Test
|
||||
fun `find annotation in annotated class`() {
|
||||
assertNotNull(TestClasses.Annotation2::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `find annotation`() {
|
||||
assertNotNull(TestClasses.AnnotatedClass::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `find annotation recursively in super class`() {
|
||||
assertNotNull(TestClasses.AnnotatedClass2::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `find annotation recursively in super class with annotation`() {
|
||||
assertNotNull(TestClasses.AnnotatedTestClass3::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `don't find unknown annotation in annotated class`() {
|
||||
assertNull(TestClasses.AnnotatedClass::class.findAnnotationRecursively(TestClasses.UnknownAnnotation::class))
|
||||
}
|
||||
|
||||
object TestClasses {
|
||||
annotation class Annotation
|
||||
|
||||
@Annotation
|
||||
annotation class Annotation2
|
||||
|
||||
annotation class UnknownAnnotation
|
||||
|
||||
@Annotation
|
||||
abstract class AnnotatedClass
|
||||
|
||||
@Annotation2
|
||||
class AnnotatedTestClass3
|
||||
|
||||
abstract class AnnotatedClass2 : AnnotatedClass()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue