问题描述
class SomeDetector : Detector(),SourceCodeScanner {
override fun getApplicableConstructorTypes(): List<String>? {
return listof(PARENT_CLASS)
}
override fun visitConstructor(context: JavaContext,node: UCallExpression,constructor: PsiMethod) {
// blabla...
}
}
好吧,我甚至成功地将lint应用于每个类的各个构造函数。
但是,我要验证的类有数百种,它们都继承了一个公共接口。
所以我想验证all classes inheriting the interface I specified
的构造函数。
我要验证的类具有android依赖关系,因此不能在像Linux库这样的lint模块中直接使用像反射之类的库。
您能帮我满足我的要求吗?
解决方法
我试了你的问题。我检查了批注中的值和所使用的参数是否相等。您可以调整代码以适合您的要求。这是一个示例Detector
类,其中我已经使用注释提供了解释。您可以对此进行改进。
class InvalidConstructorCallDetector : Detector(),Detector.UastScanner {
// Check for call expressions
override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)
override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
override fun visitCallExpression(node: UCallExpression) {
// Check if call is constructor call and if the class referenced inherits your interface
if (node.isConstructorCall() &&
context.doesInherit(node,"com.example.android.YourInterface")
) {
val constructor = node.resolve()!!
// Get the first parameter. You may use a loop and check for all parameter or whatever you require
val param = constructor.parameterList.parameters[0]
// Get your annotation
val paramAnnotation =
param.getAnnotation("com.example.android.YourAnnotation")!!
// Get the value you specified in the annotation for the constructor declaration
val attributeValue = paramAnnotation.findAttributeValue("value")!!.text.toInt()
// Get the argument used for first parameter. Again,you can have this in a loop and use index
val argumentValue = node.getArgumentForParameter(0)!!.evaluate().toString().toInt()
if (attributeValue != argumentValue) // Checking for equality. Perform whatever check you want
{
context.report(
ISSUE,node,context.getNameLocation(node),"Argument value($argumentValue) is invalid. Valid argument: $attributeValue"
)
}
}
}
}
// Check to see if class referenced by constructor call implements interface
private fun JavaContext.doesInherit(node: UCallExpression,typeName: String): Boolean {
for (type in node.classReference!!.getExpressionType()!!.superTypes) {
if (evaluator.typeMatches(type,typeName)) return true
}
return false
}
companion object {
val ISSUE = Issue.create(
"InvalidConstructorCall","Invalid arguments in constructor call","Only values defined in annotation in constructor declaration are allowed",Category.CORRECTNESS,10,Severity.ERROR,Implementation(
InvalidConstructorCallDetector::class.java,EnumSet.of(Scope.JAVA_FILE)
)
)
}
}