Added NameConditions function

This commit is contained in:
2022-05-16 03:58:15 +08:00
parent 3a1f6e6cb7
commit 48af06b2e7
9 changed files with 662 additions and 6 deletions

View File

@@ -60,6 +60,8 @@
[filename](public/ModifierRules.md ':include')
[filename](public/NameConditions.md ':include')
[filename](public/HookClass.md ':include')
[filename](public/VariousClass.md ':include')

View File

@@ -114,6 +114,24 @@ fun name(value: String): IndexTypeCondition
!> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。
### name [method]
```kotlin
inline fun name(initiate: NameConditions.() -> Unit): IndexTypeCondition
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 设置 `Field` 名称条件。
!> 若不填写名称则必须存在一个其它条件,默认模糊查找并取第一个匹配的 `Field`
!> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。
### type [method]
```kotlin

View File

@@ -158,6 +158,24 @@ fun name(value: String): IndexTypeCondition
!> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。
### name [method]
```kotlin
inline fun name(initiate: NameConditions.() -> Unit): IndexTypeCondition
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 设置 `Method` 名称条件。
!> 若不填写名称则必须存在一个其它条件,默认模糊查找并取第一个匹配的 `Method`
!> 存在多个 `IndexTypeCondition` 时除了 `order` 只会生效最后一个。
### paramCount [method]
```kotlin

View File

@@ -0,0 +1,191 @@
## NameConditions [class]
```kotlin
class NameConditions
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 这是一个模糊 `Member` 名称匹配实现类
可对 R8 混淆后的 `Member` 进行更加详细的定位。
### equalsOf
```kotlin
fun equalsOf(other: String, isIgnoreCase: Boolean)
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 完全字符匹配。
### startsWith
```kotlin
fun startsWith(prefix: String, startIndex: Int, isIgnoreCase: Boolean)
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 起始字符匹配。
### endsWith
```kotlin
fun endsWith(suffix: String, isIgnoreCase: Boolean)
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 结束字符匹配。
### contains
```kotlin
fun contains(other: String, isIgnoreCase: Boolean)
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 包含字符匹配。
### matches
```kotlin
fun matches(regex: String)
```
```kotlin
fun matches(regex: Regex)
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 正则字符匹配。
### thisSynthetic0
```kotlin
fun thisSynthetic0()
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 标识为匿名类的主类调用对象。
### onlySymbols
```kotlin
fun onlySymbols()
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 标识为只有符号。
### onlyLetters
```kotlin
fun onlyLetters()
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 标识为只有字母。
### onlyNumbers
```kotlin
fun onlyNumbers()
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 标识为只有数字。
### onlyLettersNumbers
```kotlin
fun onlyLettersNumbers()
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 标识为只有字母或数字。
### onlyLowercase
```kotlin
fun onlyLowercase()
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 标识为只有小写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。
### onlyUppercase
```kotlin
fun onlyUppercase()
```
**变更记录**
`v1.0.88` `新增`
**功能描述**
> 标识为只有大写字母。
在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符。

View File

@@ -245,6 +245,86 @@ Test::class.java.method {
!> 当前查询的 `Method` 除非指定 `superClass` 条件,否则只能查询到当前 `Class``Method`
### 模糊查询
如果我们想查询一个方法名称,但是又不确定它在每个版本中是否发生变化,此时我们就可以使用模糊查询功能。
假设我们要得到 `Class` 中的 `doTask` 方法,可以使用如下实现。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val instance = Test()
// 使用 YukiHookAPI 调用并执行
Test::class.java.method {
name {
// 设置名称不区分大小写
equalsOf(other = "dotask", isIgnoreCase = true)
}
param(StringType)
}.get(instance).call("task_name")
```
已知当前 `Class` 中仅有一个 `doTask` 方法,我们还可以判断方法名称仅包含其中指定的字符。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val instance = Test()
// 使用 YukiHookAPI 调用并执行
Test::class.java.method {
name {
// 仅包含 oTas
contains(other = "oTas")
}
param(StringType)
}.get(instance).call("task_name")
```
我们还可以根据首尾字符串进行判断。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val instance = Test()
// 使用 YukiHookAPI 调用并执行
Test::class.java.method {
name {
// 开头包含 do
startsWith(prefix = "do")
// 结尾包含 Task
endsWith(suffix = "Task")
}
param(StringType)
}.get(instance).call("task_name")
```
通过观察发现这个方法名称中只包含字母,我们还可以再增加一个精确的查询条件。
> 示例如下
```kotlin
// 假设这就是这个 Class 的实例
val instance = Test()
// 使用 YukiHookAPI 调用并执行
Test::class.java.method {
name {
// 开头包含 do
startsWith(prefix = "do")
// 结尾包含 Task
endsWith(suffix = "Task")
// 仅包含字母
onlyLetters()
}
param(StringType)
}.get(instance).call("task_name")
```
更多用法可参考 [NameConditions](api/document?id=nameconditions-class)。
### 静态字节码
有些方法和变量在 `Class` 中是静态的实现,这个时候,我们不需要传入实例就可以调用它们。

View File

@@ -35,6 +35,7 @@ import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreater
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
import com.highcapable.yukihookapi.hook.core.finder.type.NameConditions
import com.highcapable.yukihookapi.hook.factory.hasExtends
import com.highcapable.yukihookapi.hook.utils.ReflectionTool
import com.highcapable.yukihookapi.hook.utils.runBlocking
@@ -64,6 +65,10 @@ class FieldFinder(
@PublishedApi
internal var modifiers: ModifierRules? = null
/** [NameConditions] 实例 */
@PublishedApi
internal var nameConditions: NameConditions? = null
/**
* 设置 [Field] 名称
*
@@ -114,6 +119,20 @@ class FieldFinder(
return IndexTypeCondition(IndexConfigType.MATCH)
}
/**
* 设置 [Field] 名称条件
*
* - ❗若不填写名称则必须存在一个其它条件 - 默认模糊查找并取第一个匹配的 [Field]
*
* - ❗存在多个 [BaseFinder.IndexTypeCondition] 时除了 [order] 只会生效最后一个
* @param initiate 方法体
* @return [BaseFinder.IndexTypeCondition]
*/
inline fun name(initiate: NameConditions.() -> Unit): IndexTypeCondition {
nameConditions = NameConditions().apply(initiate)
return IndexTypeCondition(IndexConfigType.MATCH)
}
/**
* 设置 [Field] 类型
*
@@ -151,8 +170,12 @@ class FieldFinder(
override fun build(isBind: Boolean) = try {
if (classSet != null) {
runBlocking {
memberInstance =
ReflectionTool.findField(usedClassSet, orderIndex, matchIndex, name, modifiers, type.compat(), isFindInSuperClass)
memberInstance = ReflectionTool.findField(
usedClassSet, orderIndex,
matchIndex, name,
modifiers, nameConditions,
type.compat(), isFindInSuperClass
)
}.result { onHookLogMsg(msg = "Find Field [${memberInstance}] takes ${it}ms [${hookTag}]") }
Result()
} else Result(isNoSuch = true, Throwable("classSet is null"))

View File

@@ -34,6 +34,7 @@ import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.core.YukiMemberHookCreater
import com.highcapable.yukihookapi.hook.core.finder.base.BaseFinder
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
import com.highcapable.yukihookapi.hook.core.finder.type.NameConditions
import com.highcapable.yukihookapi.hook.factory.hasExtends
import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
@@ -71,6 +72,10 @@ class MethodFinder(
@PublishedApi
internal var modifiers: ModifierRules? = null
/** [NameConditions] 实例 */
@PublishedApi
internal var nameConditions: NameConditions? = null
/**
* 设置 [Method] 名称
*
@@ -156,6 +161,20 @@ class MethodFinder(
return IndexTypeCondition(IndexConfigType.MATCH)
}
/**
* 设置 [Method] 名称条件
*
* - ❗若不填写名称则必须存在一个其它条件 - 默认模糊查找并取第一个匹配的 [Method]
*
* - ❗存在多个 [BaseFinder.IndexTypeCondition] 时除了 [order] 只会生效最后一个
* @param initiate 方法体
* @return [BaseFinder.IndexTypeCondition]
*/
inline fun name(initiate: NameConditions.() -> Unit): IndexTypeCondition {
nameConditions = NameConditions().apply(initiate)
return IndexTypeCondition(IndexConfigType.MATCH)
}
/**
* 设置 [Method] 参数个数
*
@@ -204,8 +223,8 @@ class MethodFinder(
*/
private val result
get() = ReflectionTool.findMethod(
usedClassSet, orderIndex, matchIndex,
name, modifiers, returnType.compat(),
usedClassSet, orderIndex, matchIndex, name,
modifiers, nameConditions, returnType.compat(),
paramCount, paramTypes, isFindInSuperClass
)

View File

@@ -0,0 +1,268 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/5/16.
*/
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
package com.highcapable.yukihookapi.hook.core.finder.type
import java.lang.reflect.Field
import java.lang.reflect.Member
import java.lang.reflect.Method
/**
* 这是一个模糊 [Member] 名称匹配实现类
*
* 可对 R8 混淆后的 [Member] 进行更加详细的定位
*/
class NameConditions {
/** 完全字符匹配条件 */
private var cdsEqualsOf: Pair<String, Boolean>? = null
/** 起始字符匹配条件 */
private var cdsStartsWith: Triple<String, Int, Boolean>? = null
/** 结束字符匹配条件 */
private var cdsEndsWith: Pair<String, Boolean>? = null
/** 包含字符匹配条件 */
private var cdsContains: Pair<String, Boolean>? = null
/** 正则字符匹配条件 */
private var cdsMatches: Regex? = null
/** 标识为匿名类的主类调用对象条件 */
private var isThisSynthetic0 = false
/** 标识为只有符号条件 */
private var isOnlySymbols = false
/** 标识为只有字母条件 */
private var isOnlyLetters = false
/** 标识为只有数字条件 */
private var isOnlyNumbers = false
/** 标识为只有字母或数字条件 */
private var isOnlyLettersNumbers = false
/** 标识为只有小写字母条件 */
private var isOnlyLowercase = false
/** 标识为只有大写字母条件 */
private var isOnlyUppercase = false
/**
* 完全字符匹配
*
* 例如匹配 catMonitor 可设置为 equalsOf(other = "catMonitor")
*
* @param other 字符匹配
* @param isIgnoreCase 是否忽略字符中的大小写 - 默认否
*/
fun equalsOf(other: String, isIgnoreCase: Boolean = false) {
cdsEqualsOf = Pair(other, isIgnoreCase)
}
/**
* 起始字符匹配
*
* 例如匹配 catMonitor 可设置为 startsWith(prefix = "cat")
*
* @param prefix 起始字符匹配
* @param startIndex 起始字符下标 - 默认从 0 开始
* @param isIgnoreCase 是否忽略字符中的大小写 - 默认否
*/
fun startsWith(prefix: String, startIndex: Int = 0, isIgnoreCase: Boolean = false) {
cdsStartsWith = Triple(prefix, startIndex, isIgnoreCase)
}
/**
* 结束字符匹配
*
* 例如匹配 catMonitor 可设置为 endsWith(suffix = "Monitor")
*
* @param suffix 结束字符匹配
* @param isIgnoreCase 是否忽略字符中的大小写 - 默认否
*/
fun endsWith(suffix: String, isIgnoreCase: Boolean = false) {
cdsEndsWith = Pair(suffix, isIgnoreCase)
}
/**
* 包含字符匹配
*
* 例如匹配 catMonitor 可设置为 contains(other = "atMoni")
*
* @param other 包含字符匹配
* @param isIgnoreCase 是否忽略字符中的大小写 - 默认否
*/
fun contains(other: String, isIgnoreCase: Boolean = false) {
cdsContains = Pair(other, isIgnoreCase)
}
/**
* 正则字符匹配
*
* @param regex 正则字符
*/
fun matches(regex: String) {
cdsMatches = regex.toRegex()
}
/**
* 正则字符匹配
*
* @param regex 正则字符
*/
fun matches(regex: Regex) {
cdsMatches = regex
}
/**
* 标识为匿名类的主类调用对象
*
* 它的名称形态通常为this$0
*
* 你可以使用 [matches] 方法进行更详细的正则匹配
*/
fun thisSynthetic0() {
isThisSynthetic0 = true
}
/**
* 标识为只有符号
*
* 筛选仅包含 _、-、?、!、,、.、<、> 等符号以及特殊符号
*
* 你可以使用 [matches] 方法进行更详细的正则匹配
*/
fun onlySymbols() {
isOnlySymbols = true
}
/**
* 标识为只有字母
*
* 在没有 [onlyLowercase] 以及 [onlyUppercase] 的条件下筛选仅包含 26 个大小写英文字母
*
* 你可以使用 [matches] 方法进行更详细的正则匹配
*/
fun onlyLetters() {
isOnlyLetters = true
}
/**
* 标识为只有数字
*
* 筛选仅包含 0-9 阿拉伯数字
*
* 你可以使用 [matches] 方法进行更详细的正则匹配
*/
fun onlyNumbers() {
isOnlyNumbers = true
}
/**
* 标识为只有字母或数字
*
* 融合条件 [onlyLetters] 和 [onlyNumbers]
*
* 你可以使用 [matches] 方法进行更详细的正则匹配
*/
fun onlyLettersNumbers() {
isOnlyLettersNumbers = true
}
/**
* 标识为只有小写字母
*
* 在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符
*
* 你可以使用 [matches] 方法进行更详细的正则匹配
*/
fun onlyLowercase() {
isOnlyLowercase = true
}
/**
* 标识为只有大写字母
*
* 在没有其它条件的情况下设置此条件允许判断对象存在字母以外的字符
*
* 你可以使用 [matches] 方法进行更详细的正则匹配
*/
fun onlyUppercase() {
isOnlyUppercase = true
}
/**
* 对比 [Member] 类型是否符合条件
* @param member 实例 - 只支持 [Method]、[Field]
* @return [Boolean] 是否符合条件
*/
@PublishedApi
internal fun contains(member: Member): Boolean {
var conditions = true
when (member) {
is Method -> member.name
is Field -> member.name
else -> ""
}.also {
if (isThisSynthetic0) conditions = conditions && it == "this$0"
if (isOnlySymbols) conditions = conditions && it.matches("[*,.:~`'\"|/\\\\?!^()\\[\\]{}%@#$&\\-_+=<>]+".toRegex())
if (isOnlyLetters) conditions = conditions && it.matches("[a-zA-Z]+".toRegex())
if (isOnlyNumbers) conditions = conditions && it.matches("[0-9]+".toRegex())
if (isOnlyLettersNumbers) conditions = conditions && it.matches("[a-zA-Z0-9]+".toRegex())
if (isOnlyLowercase) conditions = conditions && it.matches("[a-z]+".toRegex())
if (isOnlyUppercase) conditions = conditions && it.matches("[A-Z]+".toRegex())
if (cdsEqualsOf != null) cdsEqualsOf?.apply { conditions = conditions && it.equals(first, second) }
if (cdsStartsWith != null) cdsStartsWith?.apply { conditions = conditions && it.startsWith(first, second, third) }
if (cdsEndsWith != null) cdsEndsWith?.apply { conditions = conditions && it.endsWith(first, second) }
if (cdsContains != null) cdsContains?.apply { conditions = conditions && it.contains(first, second) }
if (cdsMatches != null) cdsMatches?.apply { conditions = conditions && it.matches(regex = this) }
}
return conditions
}
override fun toString(): String {
var conditions = ""
if (isThisSynthetic0) conditions += "<ThisSynthetic0> "
if (isOnlySymbols) conditions += "<OnlySymbols> "
if (isOnlyLetters) conditions += "<OnlyLetters> "
if (isOnlyNumbers) conditions += "<OnlyNumbers> "
if (isOnlyLettersNumbers) conditions += "<OnlyLettersNumbers> "
if (isOnlyLowercase) conditions += "<OnlyLowercase> "
if (isOnlyUppercase) conditions += "<OnlyUppercase> "
if (cdsEqualsOf != null) cdsEqualsOf?.apply { conditions += "<EqualsOf:[other: $first, isIgnoreCase: $second]> " }
if (cdsStartsWith != null) cdsStartsWith?.apply { conditions += "<StartsWith:[prefix: $first, startIndex: $second, isIgnoreCase: $third]> " }
if (cdsEndsWith != null) cdsEndsWith?.apply { conditions += "<EndsWith:[suffix: $first, isIgnoreCase: $second]> " }
if (cdsContains != null) cdsContains?.apply { conditions += "<Contains:[other: $first, isIgnoreCase: $second]> " }
if (cdsMatches != null) cdsMatches?.apply { conditions += "<Matches:[regex: $this]> " }
return "[${conditions.trim()}]"
}
}

View File

@@ -28,6 +28,7 @@
package com.highcapable.yukihookapi.hook.utils
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
import com.highcapable.yukihookapi.hook.core.finder.type.NameConditions
import com.highcapable.yukihookapi.hook.factory.hasExtends
import com.highcapable.yukihookapi.hook.store.MemberCacheStore
import com.highcapable.yukihookapi.hook.type.defined.UndefinedType
@@ -52,6 +53,7 @@ internal object ReflectionTool {
* @param matchIndex 字节码筛选下标
* @param name 变量名称
* @param modifiers 变量描述
* @param nameConditions 名称查找条件
* @param type 变量类型
* @param isFindInSuperClass 是否在未找到后继续在当前 [classSet] 的父类中查找
* @return [Field]
@@ -64,6 +66,7 @@ internal object ReflectionTool {
matchIndex: Pair<Int, Boolean>?,
name: String,
modifiers: ModifierRules?,
nameConditions: NameConditions?,
type: Class<*>?,
isFindInSuperClass: Boolean
): Field {
@@ -77,9 +80,11 @@ internal object ReflectionTool {
var typeIndex = -1
var nameIndex = -1
var modifyIndex = -1
var nameCdsIndex = -1
val typeLastIndex = if (type != null && matchIndex != null) filter { type == it.type }.lastIndex else -1
val nameLastIndex = if (name.isNotBlank() && matchIndex != null) filter { name == it.name }.lastIndex else -1
val modifyLastIndex = if (modifiers != null && matchIndex != null) filter { modifiers.contains(it) }.lastIndex else -1
val nameCdsLastIndex = if (nameConditions != null && matchIndex != null) filter { nameConditions.contains(it) }.lastIndex else -1
forEachIndexed { p, it ->
var isMatched = false
var conditions = true
@@ -113,6 +118,16 @@ internal object ReflectionTool {
abs(matchIndex.first) == (modifyLastIndex - modifyIndex) && matchIndex.second) ||
(modifyLastIndex == modifyIndex && matchIndex.second.not()))
}
if (nameConditions != null)
conditions = (conditions && nameConditions.contains(it)).let {
if (it) nameCdsIndex++
isMatched = true
it && (matchIndex == null ||
(matchIndex.first >= 0 && matchIndex.first == nameCdsIndex && matchIndex.second) ||
(matchIndex.first < 0 &&
abs(matchIndex.first) == (nameCdsLastIndex - nameCdsIndex) && matchIndex.second) ||
(nameCdsLastIndex == nameCdsIndex && matchIndex.second.not()))
}
if (orderIndex != null) conditions =
(conditions && ((orderIndex.first >= 0 && orderIndex.first == p && orderIndex.second) ||
(orderIndex.first < 0 && abs(orderIndex.first) == (lastIndex - p) && orderIndex.second) ||
@@ -128,7 +143,7 @@ internal object ReflectionTool {
findField(
classSet.superclass,
orderIndex, matchIndex,
name, modifiers,
name, modifiers, nameConditions,
type, isFindInSuperClass = true
)
else throw NoSuchFieldError(
@@ -143,6 +158,10 @@ internal object ReflectionTool {
matchIndex.second.not() -> "matchIndex:[last] "
else -> "matchIndex:[${matchIndex.first}] "
} +
when (nameConditions) {
null -> ""
else -> "nameConditions:$nameConditions "
} +
"name:[${name.takeIf { it.isNotBlank() } ?: "unspecified"}] " +
"type:[${type ?: "unspecified"}] " +
"modifiers:${modifiers ?: "[]"} " +
@@ -159,6 +178,7 @@ internal object ReflectionTool {
* @param matchIndex 字节码筛选下标
* @param name 方法名称
* @param modifiers 方法描述
* @param nameConditions 名称查找条件
* @param returnType 方法返回值
* @param paramCount 方法参数个数
* @param paramTypes 方法参数类型
@@ -173,6 +193,7 @@ internal object ReflectionTool {
matchIndex: Pair<Int, Boolean>?,
name: String,
modifiers: ModifierRules?,
nameConditions: NameConditions?,
returnType: Class<*>?,
paramCount: Int,
paramTypes: Array<out Class<*>>?,
@@ -193,6 +214,7 @@ internal object ReflectionTool {
var paramCountIndex = -1
var nameIndex = -1
var modifyIndex = -1
var nameCdsIndex = -1
val returnTypeLastIndex =
if (returnType != null && matchIndex != null) filter { returnType == it.returnType }.lastIndex else -1
val paramCountLastIndex =
@@ -201,6 +223,7 @@ internal object ReflectionTool {
if (paramTypes != null && matchIndex != null) filter { arrayContentsEq(paramTypes, it.parameterTypes) }.lastIndex else -1
val nameLastIndex = if (name.isNotBlank() && matchIndex != null) filter { name == it.name }.lastIndex else -1
val modifyLastIndex = if (modifiers != null && matchIndex != null) filter { modifiers.contains(it) }.lastIndex else -1
val nameCdsLastIndex = if (nameConditions != null && matchIndex != null) filter { nameConditions.contains(it) }.lastIndex else -1
forEachIndexed { p, it ->
var isMatched = false
var conditions = true
@@ -254,6 +277,16 @@ internal object ReflectionTool {
abs(matchIndex.first) == (modifyLastIndex - modifyIndex) && matchIndex.second) ||
(modifyLastIndex == modifyIndex && matchIndex.second.not()))
}
if (nameConditions != null)
conditions = (conditions && nameConditions.contains(it)).let {
if (it) nameCdsIndex++
isMatched = true
it && (matchIndex == null ||
(matchIndex.first >= 0 && matchIndex.first == nameCdsIndex && matchIndex.second) ||
(matchIndex.first < 0 &&
abs(matchIndex.first) == (nameCdsLastIndex - nameCdsIndex) && matchIndex.second) ||
(nameCdsLastIndex == nameCdsIndex && matchIndex.second.not()))
}
if (orderIndex != null) conditions =
(conditions && ((orderIndex.first >= 0 && orderIndex.first == p && orderIndex.second) ||
(orderIndex.first < 0 && abs(orderIndex.first) == (lastIndex - p) && orderIndex.second) ||
@@ -269,7 +302,7 @@ internal object ReflectionTool {
findMethod(
classSet.superclass,
orderIndex, matchIndex,
name, modifiers,
name, modifiers, nameConditions,
returnType, paramCount,
paramTypes, isFindInSuperClass = true
)
@@ -285,6 +318,10 @@ internal object ReflectionTool {
matchIndex.second.not() -> "matchIndex:[last] "
else -> "matchIndex:[${matchIndex.first}] "
} +
when (nameConditions) {
null -> ""
else -> "nameConditions:$nameConditions "
} +
"name:[${name.takeIf { it.isNotBlank() } ?: "unspecified"}] " +
"paramCount:[${paramCount.takeIf { it >= 0 } ?: "unspecified"}] " +
"paramTypes:[${paramTypes.typeOfString()}] " +