Запуск Checker Framework на Android

Я хочу использовать Checker Framework для статического анализа моего приложения — проверки ошибок Nullability, ошибок ограничений пользовательского интерфейса и т. д. во время выполнения. Я следовал инструкциям на странице https://checkerframework.org/manual/#android-gradle. чтобы попытаться запустить его, но я получаю сообщение об ошибке, что checkTypes не является задачей. Думаю, я правильно следовал инструкциям и исправил несоответствие заглавных букв, которое у них было. Любые идеи, как это исправить? Мой build.gradle ниже:

buildscript {
    repositories {
        maven { url 'https://maven.fabric.io/public' }
    }

    dependencies {
        classpath 'io.fabric.tools:gradle:1.+'
    }
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'

repositories {
    maven { url 'https://maven.fabric.io/public' }
    google()
}

apply plugin: 'jacoco'
apply plugin: 'com.getkeepsafe.dexcount'

gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
        options.compilerArgs << "-Xmaxerrs" << "500"
    }
}

android {
    compileSdkVersion 25
    buildToolsVersion '26.0.2'
    defaultConfig {
        applicationId "com.handshake.hsdm"
        minSdkVersion 19
        targetSdkVersion 25
        versionCode 35
        versionName "0.0.35"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            testCoverageEnabled = false
        }
        debug {
            testCoverageEnabled = false
        }
        checkTypes {
            javaCompileOptions.annotationProcessorOptions.
                    classNames.add("org.checkerframework.checker.guieffect.GuiEffectChecker")
            // You can pass options like so:
            // javaCompileOptions.annotationProcessorOptions.arguments.put("warns", "")
        }

    }
    dexOptions {
        preDexLibraries = false
    }
    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
        }
    }
    packagingOptions {
        //These files constantly step on each other from multiple libraries, don't include them
        exclude 'META-INF/ASL2.0'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/*'
        exclude 'plugin.xml'
        exclude 'plugin.properties'
        exclude 'about_files/LICENSE-2.0.txt'
    }
    testOptions {
        unitTests.all {
            jacoco {
                includeNoLocationClasses = true
            }
        }
    }
    jacoco {
        version = '0.7.3.201502191951'
    }
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:2.0.1'
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

}
configurations {
    checkerFrameworkAnnotatedJDK {
        description = 'a copy of JDK classes with Checker Framework type qualifers inserted'
    }
}

task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {

    reports {
        xml.enabled = true
        html.enabled = true
    }

    def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*',
                      'com/handshake/hsdm/demo/**','com/handshake/hsdm/localstorage/schema1/*Dao*',
                      'com/handshake/hsdm/localstorage/schema1/*Factory*', 'com/handshake/hsdm/dagger2',
                      '**/*Module*', '**/*_Factory*', '**/*_MembersInjector*'
    ]
    def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/debug", excludes: fileFilter)
    def mainSrc = "${project.projectDir}/src/main/java"

    sourceDirectories = files([mainSrc])
    classDirectories = files([debugTree])
    executionData = fileTree(dir: "$buildDir", includes: [
            "jacoco/testDebugUnitTest.exec",
            "outputs/code-coverage/connected/*coverage.ec"
    ])

    afterEvaluate {
        classDirectories = files(classDirectories.files.collect {
            fileTree(dir: it, exclude: ['com/handshake/hsdm/demo/**'])
        })
    }
}
dependencies {
//Clipping dependencies 

    ext.checkerFrameworkVersion = '2.2.1'
    implementation "org.checkerframework:checker-qual:${checkerFrameworkVersion}"
    annotationProcessor "org.checkerframework:checker:${checkerFrameworkVersion}"
    checkerFrameworkAnnotatedJDK "org.checkerframework:jdk8:${checkerFrameworkVersion}"

}
apply plugin: 'com.google.gms.google-services'

gradle.projectsEvaluated {
    tasks.withType(JavaCompile).all { compile ->
        if (compile.name.contains("checkTypes")) {
            compile.options.compilerArgs += [
                    "-Xbootclasspath/p:${configurations.checkerFrameworkAnnotatedJDK.asPath}"
            ]
        }
    }
}

Изменить: для будущих читателей - строка javaCompileOptions.annotationProcessorOptions.classNames +=["org.checkerframework.checker.nullness.NullnessChecker"] кажется проблемой. удаление его запускает кинжал и другие процессоры аннотаций, но, очевидно, не запустит средство проверки.


person Gabe Sechan    schedule 30.10.2017    source источник
comment
Где и как вы получаете ошибку?   -  person CommonsWare    schedule 31.10.2017
comment
При запуске gradlew checkTypes. Точное сообщение: * Что пошло не так: Задача «checkTypes» не найдена в корневом проекте «HSDM».   -  person Gabe Sechan    schedule 31.10.2017
comment
В их документах говорится, что для запуска чекеров используйте вариант checkTypes. Строка под этим gradlew checkTypes неверна, так как вы строите тип сборки не в большей степени, чем вы делаете debug сборку через gradlew debug. Это gradlew assembleDebug или gradlew installDebug. Однако я никогда не пробовал тип сборки смешанного регистра, такой как `checkTypes, поэтому я не уверен, как собирается имя задачи. Загляните в свой инструмент Gradle в Android Studio и посмотрите, какие там задачи, или перечислите задачи в командной строке и посмотрите, что появится.   -  person CommonsWare    schedule 31.10.2017
comment
Есть assembleCheckTypes. Запуск запускает сборку, но не выполняет никакой обработки аннотаций — все мои классы AutoFactory отсутствуют, что ломает остальную часть Dagger.   -  person Gabe Sechan    schedule 31.10.2017
comment
Я подозреваю, что для ответа на этот вопрос потребуется рука, имеющая опыт игры в шашки. По крайней мере, я понятия не имею об этом — извините!   -  person CommonsWare    schedule 31.10.2017
comment
У одного из проверяющих была догадка, которая оказалась верной: если вы укажете AnnotationProcessor, то он перезапишет набор по умолчанию, и все AnnotationProcessors должны быть указаны. Поэтому мне пришлось вручную добавить AutoFactory и Dagger. Отлично работает, я буду очень рад, что время компиляции будет проверяться на нуль и эффект пользовательского интерфейса.   -  person Gabe Sechan    schedule 01.11.2017


Ответы (1)


Таким образом, если вы укажете 1 процессор аннотаций через имена классов, он перезапишет любые другие. Поэтому мне пришлось указать еще и кинжал, и автозавод. Затем я могу запустить его из Android Studio как сборку или из командной строки как:

gradlew assembleCheckTypes
person Gabe Sechan    schedule 01.11.2017