在我们之前的项目中,我们有一个名为 AbstractActor 的类要被继承来做特定的事情,我们的一些开发人员可能会将其引用保存为构造的 valOrVar 参数或 KTProperty,这最终导致了垃圾收集灾难,actor 不能被收集,因为它被引用并且内存使用率飙升。所以我的领导要求我创建一个新规则来防止这种情况发生,我尝试了很多方法,但我无法让 KClass 确定它是 isAssignableFrom 还是 isSubclassOf 到 AbstractActor 类。这是我创建的测试示例
class ActorRefTest {
@Test
fun noExplicitlyReferencingActorRule() {
val env = createEnvironment()
val findings = NoExplicitlyReferencingActorRule(Config.empty).compileAndLintWithContext(
env.env, """
package testRule
open class TypedActor : AbstractActor() {
override fun receive(msg: Any) {
}
}
class Typed1Actor : TypedActor() {
}
abstract class AbstractActor {
abstract fun receive(msg: Any)
}
//@Suppress("NoExplicitlyReferencingActorRule")
class ExplicitlyReferencingActor(val actor: Typed1Actor, val isEnabled: Boolean) {
// lateinit var actor2: AbstractActor
val isEnabled : Boolean = false
}
""".trimIndent()
)
findings.forEach {
println(it)
}
assert(findings.isNotEmpty())
}
}
这是我创建的规则
package testRuleSet
import io.gitlab.arturbosch.detekt.api.*
import io.gitlab.arturbosch.detekt.rules.identifierName
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.typeBinding.createTypeBindingForReturnType
class NoExplicitlyReferencingActorRule(config: Config) : Rule(config) {
override val issue: Issue = Issue(
javaClass.simpleName,
Severity.Style,
"Customized-NoExplicitlyReferencingActor",
Debt.TEN_MINS,
)
override fun visitParameter(parameter: KtParameter) {
super.visitParameter(parameter)
if (parameter.hasValOrVar()) {
if (validateDeclaration(parameter)) {
reportCodeSmell(parameter)
}
}
}
private fun isSubClassOfAbsractActor(parameter: KtCallableDeclaration): Boolean {
return parameter.createTypeBindingForReturnType(bindingContext)?.type?.constructor?.supertypes?.find {
it.getJetTypeFqName(
false
) == "testRule.AbstractActor"
} != null
}
private fun validateDeclaration(declaration: KtCallableDeclaration): Boolean {
if (bindingContext == BindingContext.EMPTY) {
return false
}
return isSubClassOfAbsractActor(declaration)
}
override fun visitProperty(property: KtProperty) {
super.visitProperty(property)
if (property.isMember) {
if (validateDeclaration(property)) {
reportCodeSmell(property)
}
}
}
private fun reportCodeSmell(declaration: KtCallableDeclaration) {
report(
CodeSmell(
issue,
Entity.from(requireNotNull(declaration.colon)),
"do not hold any subclass of AbsractActor as a explicit reference"
)
)
}
}
根据我在堆栈跟踪中看到的内容,detekt 和编译器知道确切的包和标识符名称,但我无法正确理解,我在这里缺少什么?