如何打造通用可配置的自定义Lint规则

2020-10-28  本文已影响0人  不思进取的码农

如果对Lint以及如何自定义Lint规则的不了解的可以看一下我之前的一篇文章
自定义lint一篇文章就够了
想要打造通用可配置的自定义Lint规则首先我们要搞清楚两点

哪些内容可配置

可配置主要分以下两点

什么代码可通用

而lint检测匹配的内容,是根据被检测者路径来做匹配的
比如Log我们要检测的java.lang.Thread 或者com.google.gson.Gson

按照这个思路,我我可以先做一个匹配通过创建对象的一个规则

比如我们代码中,有很多可能要被替换的方法,通用的可以做一个map


class ConstructorDetector: Detector(), Detector.UastScanner {


    private var constructorMap= mapOf(
           "java.lang.Thread"  to "请用线程池创建线程,避免直接new Thread()",
            "com.google.gson.Gson" to "使用GsonUtil避免重复创建Gson对象",
    )

    companion object {
        @JvmField
        val ISSUE: Issue = Issue.create(
                "NotNewUselessObject",
                "避免直接创建不必要的对象",
                "避免直接创建不必要的对象",
                Category.CORRECTNESS,
                7,
                Severity.WARNING,
                Implementation(ConstructorDetector::class.java, Scope.JAVA_FILE_SCOPE)
        )
    }

    override fun getApplicableConstructorTypes(): List<String>? {
        return constructorMap.keys.toList()
    }

    override fun visitConstructor(context: JavaContext, node: UCallExpression, constructor: PsiMethod) {
        context.report(ISSUE, node, context.getLocation(node), getMessage(getConstructorClass(constructor)))
    }


    private fun getMessage(className: String): String {
        return constructorMap[className]?:"缺少提示"

    }

    private fun getConstructorClass(constructor: PsiMethod):String {

        var className=UastLintUtils.getQualifiedName(constructor)?:""
        return if (className.isNullOrEmpty()) {
          ""
        }else{
            className.substring(0,className.lastIndexOf(".${constructor.name}"))

        }

    }

}

当然你可以把map配置成一个json文件,通过解析json来匹配lint规则。

我们通过配置了一个通用的创建建对象通用规则,而通用方法通用属性思路大致相同

通过注解实现通用规则配置

还有一种思路是放在代码里面我们不关注 我们能不能做一个不关注对象,方法的,属性,我们只关注调用的一种通用匹配规则?

答案是有的

我们借鉴了注解@Deprecated
实现了注解@ReplaceWith


@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.TYPEALIAS)
@Retention(AnnotationRetention.SOURCE)
annotation class ReplaceWith (val message: String)

messages是我们要提示的内容
我们只有需要关心有调用的地方具有@ReplaceWith 就已经命中了我们的规则,提出去message内容做为提示语

语言限定注解

我们的项目的Java和kotlin混编的,有一些用kotlin语法糖编写的方法可能只适用于在kotlin调用,不适用与Java
而我们@ReplaceWith目前无法区分语言,为了解决这个问题。我们又定义了两种标识过滤注解

用法示例


    @ReplaceWith(message = "建议使用 asViewClick,asViewShown,")
    @ScopeKotlin
    public BaseRecord setOt(String aOt) {
        params.put(Config.KEY_OT, aOt);
        return this;
    }
    

这个例子想表达的是在Java中的setOt方法我们不做修改,但如果在kotlin使用该方法我们建议他使用@ReplaceWith中message的提示的两个方法asViewClick,asViewShown来替换

有人会问为什么我们有了通用配置方式,还要实现这种注解的方式,其实两者不冲突
当然这种使用注解的形势只适用我们工程里的代码,因为我们无法在ThreadGson里增加这个注解,所以目前我们是一起使用的

写到最后

其实 自定义lint规则 特别是注解是如何实现,我并没有把具体的实现代码贴出来,而复杂的匹配规则也比自定义通用对象的要麻烦许多,而在探索和使用lint的时候我也的确遇到了很多坑
因为没有api国内也没有相应的文档,就算有也是很几年前放到现在是不行的。所以我更多是查看lint自带的规则源码,不断的尝试,过程的确比较痛苦,但是收货也很丰富

(每天学习一点点.每天进步一点点,分享不宜路过点个赞呀,喜欢的点个关注后续更新不断)

上一篇下一篇

猜你喜欢

热点阅读