kotlin插件_Kotlin的SonarQube插件-使用ANTLR分析

kotlin插件

上周,我们使用ANTLR生成了一个库,可以分析Kotlin代码 。 现在该使用生成的API来检查特定模式了。

API概述

让我们开始看看生成的API:

  • KotlinLexer :执行词法分析
  • KotlinParser :包装代表所有Kotlin令牌的类,并处理解析错误。
  • KotlinParserVisitor :用于在Kotlin代码上实现Visitor模式的合同。 KotlinParserBaseVisitor是它的空实现,以简化子类的创建。
  • KotlinParserListener :访问Kotlin代码时与回调相关的代码的合同,其中KotlinParserBaseListener为空的实现。
解析器词法分析器类图

类图并不是简化代码编写的最佳方法。 以下代码段是非常粗糙的分析实现。 我将使用Kotlin,但可以使用与Java互操作的任何JVM语言:

valstream=CharStreams.fromString("fun main(args : Array<String>) {}") (1)
vallexer=KotlinLexer(stream) (2)
valtokens=CommonTokenStream(lexer) (3)
valparser=KotlinParser(tokens) (4)
valcontext=parser.kotlinFile() (5)
ParseTreeWalker().apply{ (6)
    walk(object: KotlinParserBaseListener(){ (7)
        overridefunenterFunctionDeclaration(ctx:KotlinParser.FunctionDeclarationContext){ (8)
            println(ctx.SimpleName().text) (9)
        }
    },context)
}

解释如下:

  1. 创建一个CharStream以便在下一行输入词法分析器。 所述CharStreams提供了大量的静态的fromXXX()方法中,每个接受一个不同的类型( StringInputStream等)
  2. 使用流实例化词法分析器
  3. 在词法分析器上实例化令牌流。 该类通过词法分析器提供流功能。
  4. 使用令牌流实例化解析器
  5. 在代码中定义入口点。 在这种情况下,它是一个Kotlin文件-可能会用于该插件。
  6. 创建将依次访问每个节点的整体walker
  7. 通过调用walk并传递所需的行为作为对象来启动访问过程
  8. 覆盖所需的功能。 此处,每次输入功能节点时都会调用它
  9. 进行所需的操作, 例如打印功能名称

显然,第1至7行只是将所有组件连接在一起的样板。 需要实现的行为应替换第8行和第9行。

第一次简单检查

在Kotlin中,如果函数返回Unit -不返回任何值,则显式声明其返回类型是可选的。 检查是否有这种明确的回报将是一个很好的规则。 以下代码段都是有效的Kotlin代码,它们是等效的-一个具有明确的返回类型,另一个不具有:

funhello1():Unit{
    println("Hello")
}

funhello2(){
    println("Hello")
}

让我们用grun以图形方式显示解析树( grun是在解释以前的帖子 )。 它产生以下内容:

解析树返回单位

可以看出,具有显式返回类型的代码片段在functionDeclaration下具有类型分支。 KotlinParser ANTLR语法文件中的代码片段确认了这一点:

functionDeclaration
  : modifiers 'fun' typeParameters?
      (type '.' | annotations)?
      SimpleName
      typeParameters? valueParameters (':' type)?
      typeConstraints
      functionBody?
      SEMI*
  ;

该规则应检查是否存在这样的返回类型,否则它不应为Unit 。 让我们以所需的效果更新上面的代码:

ParseTreeWalker().apply{
    walk(object: KotlinParserBaseListener(){
        overridefunenterFunctionDeclaration(ctx:KotlinParser.FunctionDeclarationContext){
            if(ctx.type().isNotEmpty()){ (1)
                valtypeContext=ctx.type(0) (2)
                with(typeContext.typeDescriptor().userType().simpleUserType()){ (3)
                    valtypeName=this[0].SimpleName()
                    if(typeName.symbol.text=="Unit"){ (4)
                        println("Found Unit as explicit return type "+ (5)
                        	"in function ${ctx.SimpleName()} at line ${typeName.symbol.line}")
                    }
                }
            }
        }
    },context)
}

解释如下:

  1. 检查是否有显式的返回类型,无论它是什么
  2. 足够奇怪的是,语法允许使用多值返回类型。 就拿第一个。
  3. 遵循解析树,直到最终的类型名称-有关路径的图形表示,请参考上面的解析树屏幕快照。
  4. 检查返回类型是否为Unit
  5. 在控制台中打印消息。 在下一步中,我们将在那里调用SonarQube API。

正确运行上面的代码将产生以下输出:

Found Unit as explicit return type in function hello1 at line 1

更高级的检查

在Kotlin中,以下片段都是等效的:

funhello1(name:String):String{
    return"Hello $name"
}

funhello2(name:String):String="Hello $name"

funhello3(name:String)="Hello $name"

请注意,在最后一种情况下,返回类型可以由编译器推断,而由开发人员省略。 这将是一个很好的检查:对于表达式主体,应省略返回类型。 可以使用与上述相同的技术:

  1. 使用grun显示摘录中的分析树:

    解析树返回类型表达式主体

  2. 检查差异。 明显:
    • 如上所述,没有显式返回类型的functionDeclaration错过functionDeclaration树中的type节点
    • 具有表达式主体的functionBody具有一个functionBody其第一个子代为= ,第二个子代为expression
  3. 请参考初始语法,以确保涵盖所有情况。
    functionBody
      : block
      | '=' expression
      ;
  4. 码!
    ParseTreeWalker().apply{
        walk(object: KotlinParserBaseListener(){
            overridefunenterFunctionDeclaration(ctx:KotlinParser.FunctionDeclarationContext){
                valbodyChildren=ctx.functionBody().children
                if(bodyChildren.size>1
                        &&bodyChildren[0]isTerminalNode&&bodyChildren[0].text=="="
                        &&ctx.type().isNotEmpty()){
                    valfirstChild=bodyChildren[0]asTerminalNode
                    println("Found explicit return type for expression body "+
                            "in function ${ctx.SimpleName()} at line ${firstChild.symbol.line}")
                }
            }
        },context)
    }

该代码非常不言自明,并产生以下内容:

Found explicit return type for expression body in function hello2 at line 5

翻译自: https://blog.frankel.ch/sonarqube-plugin-kotlin/2/

kotlin插件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值