Как я могу гарантировать, что правильный байт-код доступен для моего пользовательского правила плагина сонара, чтобы я не получал !unknown! для каждого типа?

Я пытался написать собственный плагин правил для 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 в поисках использования статического метода построения SQL MAX, MIN, ASC или DESC, которому передается 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.

}

Я уверен, что мне не хватает какой-то важной части головоломки, и я был бы признателен, если бы кто-нибудь сказал мне, где я ошибаюсь.

EDIT: я использую 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, что может привести к потенциальному отсутствию вещей.


person tzrlk    schedule 22.08.2016    source источник
comment
Не могли бы вы поделиться кодом, который вы анализируете? Там может быть что-то спрятано.   -  person benzonico    schedule 22.08.2016
comment
вы также можете уточнить, какую версию анализатора сонара java вы используете.   -  person benzonico    schedule 22.08.2016
comment
Я добавил обновление к вопросу.   -  person tzrlk    schedule 23.08.2016
comment
Первое, что нужно попробовать: я могу только порекомендовать вам обновиться до последней версии 4.1 (и, следовательно, LTS-версии SQ 5.6.1).   -  person benzonico    schedule 24.08.2016
comment
Да, обновил зависимость до 4.1, но она по-прежнему подбирает типы только из стандартной библиотеки Java. Перемещение библиотеки, из которой я получаю AutoLongColumn, из области test в область compile также не имеет значения.   -  person tzrlk    schedule 29.08.2016
comment
Нашел решение и добавил свой ответ. Чувак, ты мог бы подумать, что он просто возьмет то, что ему нужно, из пути к классам, под которым он работает, но нет.   -  person tzrlk    schedule 29.08.2016


Ответы (1)


Итак, оказывается, что способ получить доступные типы — использовать maven (или любой другой инструмент, который вы используете), чтобы скопировать необходимые банки в каталог, затем превратить партию в список файлов и передать это тесту верификатор.

Например, давайте представим, что мы пытаемся найти использование 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>

Это выполнение поместит jar-файл joda-time в каталог target/dependency. Затем вы должны перечислить банки в этом каталоге и добавить их в свою тестовую проверку (мы предполагаем, что вы назвали свой верификатор «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 доступны во время анализа.

person tzrlk    schedule 29.08.2016
comment
Следует отметить одну вещь: для этого есть веская причина: вы можете не захотеть добавлять зависимость в свой проект (даже в тестах из-за возможных конфликтов версий классов), потому что типы, которые вы хотите тестировать, могут не быть частью вашего пользовательского проект правил (например, тестирование JPA и т. д.) - person benzonico; 29.08.2016