我怎样才能确保正确的字节码可用于我的自定义声纳插件规则,所以我不会得到 !unknown!对于每种类型?

How can I ensure that the right bytecode is available to my custom sonar plugin rule, so I don't get !unknown! for every type?

我一直在尝试为 Sonarqube ~5.4 编写一个自定义规则插件,虽然我已经实现并运行了一些规则,但是那些依赖于标准库之外的类型的规则依赖于各种杂技字符串匹配。

我正在使用 sonar-packaging-maven-plugin 进行打包:

<plugin>
    <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
    <artifactId>sonar-packaging-maven-plugin</artifactId>
    <version>1.16</version>
    <configuration>
        <pluginClass>${project.groupId}.sonar.BravuraRulesPlugin</pluginClass>
        <pluginKey>SonarPluginBravura</pluginKey>
        <skipDependenciesPackaging>false</skipDependenciesPackaging>
        <basePlugin>java</basePlugin>
    </configuration>
    <executions>

        <execution>
            <phase>package</phase>
            <goals>
                <goal>sonar-plugin</goal>
            </goals>
        </execution>

    </executions>
</plugin>

并且 运行 使用以下辅助扩展 (kotlin) 进行各种检查:

fun <T : JavaFileScanner> T.verify() {

    val workDir = System.getProperty("user.dir");
    val folder = Paths.get(workDir, "src/test/samples", this.javaClass.simpleName);

    Files.list(folder).forEach { sample ->
        try {
            if (sample.toString().endsWith(".clean.java")) {
                JavaCheckVerifier.verifyNoIssue(sample.toString(), this);

            } else {
                JavaCheckVerifier.verify(sample.toString(), this);
            }

        } catch (error: Exception) {
            throw VerificationFailedException(sample, error);
        }
    }

};

class VerificationFailedException(path: Path, error: Exception)
        : Exception("Failed to verify $path.", error);

我为该规则创建了一个 IssuableSubscriptionVisitor 子类,并访问 Tree.Kind.METHOD_INVOCATION,寻找静态 MAX、MIN、ASC 或 DESC sql 构建器方法的用途AutoLongColumn。这是为了停止将标识符字段用于订购目的。

不幸的是,即使我在 maven 'test' 类路径上有必要的库,当我尝试获取任何类型时,它们只显示为 !unknown!.

override fun visitNode(tree: Tree) {

    if (tree !is MethodInvocationTree) {
        return;
    }

    val methodSelect = tree.methodSelect();
    if (methodSelect !is IdentifierTree || methodSelect.name() !in setOf("MAX", "MIN", "ASC", "DESC")) {
        return;
    }

val firstArg = statement.arguments().first();
    if (firstArg !is MethodInvocationTree) {
        return;
    }

    val firstArgSelect = firstArg.methodSelect();
    if (firstArgSelect !is MemberSelectExpressionTree) {
        return;
    }

    if (firstArgSelect.type is UnknownType) {
        throw TableFlipException("(ノಥ益ಥ)ノ ┻━┻");
    }

    // It never gets here.

}

我确定我遗漏了一些重要的拼图,如果有人能告诉我哪里出错了,我将不胜感激。

编辑: 我正在使用 org.sonarsource.java:sonar-java-plugin:3.14 作为分析器,虽然我无法发布分析目标的所有代码(商业 IP 等) ), 这里有一些在结构上与关键部分相同的东西:

import static com.library.UtilClass.MAX;

...

query.SELECT(biggestId = MAX(address._id())) // Noncompliant
        .FROM(address)
        .WHERE(address.user_id().EQ(userId)
                .AND(address.type_id().EQ(typeId)));
...

address.id() 的类型是一个 com.library.Identifier,它包含一个 long。我希望能够访问所有方法调用,检查它们是否匹配 com.library.UtilCLass.MAX,如果匹配,请确保第一个参数不是 com.library.Identifier。没有类型信息,我必须对 _id 方法引用进行正则表达式匹配,这很容易丢失一些东西。

所以,事实证明,获得可用类型的方法是使用 maven(或您正在使用的任何工具)将所需的 jars 复制到目录中,然后将其转换为文件列表,然后将其传递给测试验证者。

例如,假设我们正在尝试查找 joda-time:

的用法
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.10</version>
    <executions>

        <execution>
            <id>copy-libs</id>
            <phase>generate-test-resources</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>

                <artifactItems>

                    <artifactItem>
                        <groupId>joda-time</groupId>
                        <artifactId>joda-time</artifactId>
                        <version>2.9.4</version>
                    </artifactItem>

                </artifactItems>

            </configuration>
        </execution>

    <executions>
</plugin>

此执行会将 joda-time jar 放入 target/dependency 目录。接下来,确保枚举该目录中的 jars,并将它们添加到测试验证中(我们假设您将验证器命名为 'JodaCheck'):

// Not at all necessary, but it makes the code later on a lot easier to read.
fun <T> Stream<T>.toList(): List<T> = this.collect({
    mutableListOf()

}, { list, item ->
    list.add(item)

}, { list, otherList ->
    list.addAll(otherList)

})

...

val workDir = System.getProperty("user.dir")
val sampleFile = Paths.get(workDir, "src/test/samples/JodaSample.java").toString()
val dependencies = Files.list(Paths.get(workDir, "target/dependency"))
        .map { it.toFile() }.toList()

JavaCheckVerifier.verify(sampleFile, JodaChecker(), dependencies)

完成后,通过测试进行调试将显示 joda-time 类 在分析期间可用。