test project confirming that lint checks are running
Bug: 177437928
Test: ./gradlew buildOnServer --dry-run 2>&1 | grep validateLint # to confirm this task runs
Test: ./gradlew validateLint
Change-Id: Ice436382f6abb3a07fd0e8ec4beee7e71e8b1457
diff --git a/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt
index 158065e..4ce1461 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt
@@ -74,17 +74,20 @@
project.rootProject.project(":lint-checks")
)
+ // The purpose of this specific project is to test that lint is running, so
+ // it contains expected violations that we do not want to trigger a build failure
+ val isTestingLintItself = (project.path == ":lint-checks:integration-tests")
+
// If -PupdateLintBaseline was set we should update the baseline if it exists
- val updateLintBaseline = hasProperty(UPDATE_LINT_BASELINE)
+ val updateLintBaseline = hasProperty(UPDATE_LINT_BASELINE) && !isTestingLintItself
// Lint is configured entirely in afterEvaluate so that individual projects cannot easily
- // disable individual checks in the DSL for any reason. That being said, when rolling out a new
- // check as fatal, it can be beneficial to set it to fatal above this comment. This allows you
- // to override it in a build script rather than messing with the baseline files. This is
- // especially relevant for checks which cause hundreds or more failures.
+ // disable individual checks in the DSL for any reason.
afterEvaluate {
lintOptions.apply {
- isAbortOnError = true
+ if (!isTestingLintItself) {
+ isAbortOnError = true
+ }
isIgnoreWarnings = true
// Workaround for b/177359055 where 27.2.0-beta04 incorrectly computes severity.
diff --git a/lint-checks/integration-tests/build.gradle b/lint-checks/integration-tests/build.gradle
new file mode 100644
index 0000000..4c80155
--- /dev/null
+++ b/lint-checks/integration-tests/build.gradle
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.BuildOnServerKt
+import androidx.build.uptodatedness.EnableCachingKt
+import org.apache.tools.ant.filters.ReplaceTokens
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+}
+
+dependencies {
+ implementation("androidx.annotation:annotation:1.0.0")
+}
+
+androidx {
+ name = "Lint Checks Integration Tests"
+ description = "This is a sample library for confirming that lint checks execute correctly, b/177437928"
+}
+
+android {
+ lintOptions {
+ // lint is supposed to detect errors in this project
+ // We don't need to see the errors in stdout
+ textOutput("${buildDir}/lint-output.txt")
+ // We don't want errors to cause lint to fail
+ abortOnError false
+ }
+}
+
+
+class CompareFilesTask extends DefaultTask {
+ @InputFile
+ File actualFile
+ @InputFile
+ File expectedFile
+
+ @TaskAction
+ def compare() {
+ def actualResults = actualFile.text
+ def expectedResults = expectedFile.text
+ if (actualResults != expectedResults) {
+ throw new GradleException("Incorrect lint results.\n" +
+ "\n" +
+ "Actual text: '" + actualResults + "'\n" +
+ "\n" +
+ "Expected text: '" + expectedResults + "'\n" +
+ "\n" +
+ "Are all lint checks running?\n" +
+ "\n" +
+ "Actual output at: " + actualFile + "\n" +
+ "Expected output at: " + expectedFile + "\n")
+ }
+ }
+}
+
+def lintOutputFile = project.file("${buildDir}/reports/lint-results-debug.xml")
+def lintOutputFileNormalized = project.file("${buildDir}/lint-results-normalized/lint-results-debug.xml.normalized")
+
+def normalizeLintOutput = tasks.register("normalizeLintOutput", Copy) {
+ from(lintOutputFile) {
+ filter { line ->
+ return line.replace("${project.rootProject.projectDir}", "\$SUPPORT")
+ }
+ }
+ into(lintOutputFileNormalized.parentFile)
+ rename(".*", lintOutputFileNormalized.name)
+ dependsOn("lintDebug")
+}
+
+def validateLint = tasks.register("validateLint", CompareFilesTask) { task ->
+ task.actualFile = lintOutputFileNormalized
+ task.expectedFile = project.file("expected-lint-results.xml")
+ EnableCachingKt.cacheEvenIfNoOutputs(task)
+ dependsOn(normalizeLintOutput)
+}
+
+BuildOnServerKt.addToBuildOnServer(project, validateLint)
diff --git a/lint-checks/integration-tests/expected-lint-results.xml b/lint-checks/integration-tests/expected-lint-results.xml
new file mode 100644
index 0000000..4820c1f
--- /dev/null
+++ b/lint-checks/integration-tests/expected-lint-results.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.2.0-beta04">
+
+ <issue
+ id="BanConcurrentHashMap"
+ severity="Error"
+ message="Detected ConcurrentHashMap usage."
+ category="Correctness"
+ priority="5"
+ summary="ConcurrentHashMap usage is not allowed"
+ explanation="ConcurrentHashMap has an issue on Android’s Lollipop release that can lead to lost updates under thread contention."
+ errorLine1="import java.util.concurrent.ConcurrentHashMap;"
+ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="$SUPPORT/lint-checks/integration-tests/src/main/java/Sample.java"
+ line="19"
+ column="1"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ severity="Fatal"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+ category="Interoperability:Kotlin Interoperability"
+ priority="6"
+ summary="Unknown nullness"
+ explanation="To improve referencing this code from Kotlin, consider adding
explicit nullness information here with either `@NonNull` or `@Nullable`.

You can set the environment variable
 `ANDROID_LINT_NULLNESS_IGNORE_DEPRECATED=true`
if you want lint to ignore classes and members that have been annotated with
`@Deprecated`."
+ url="https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+ urls="https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+ errorLine1=" public static Sample confirmIntrinisicLintChecksRun() {"
+ errorLine2=" ~~~~~~">
+ <location
+ file="$SUPPORT/lint-checks/integration-tests/src/main/java/Sample.java"
+ line="28"
+ column="19"/>
+ </issue>
+
+ <issue
+ id="UnknownNullness"
+ severity="Fatal"
+ message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+ category="Interoperability:Kotlin Interoperability"
+ priority="6"
+ summary="Unknown nullness"
+ explanation="To improve referencing this code from Kotlin, consider adding
explicit nullness information here with either `@NonNull` or `@Nullable`.

You can set the environment variable
 `ANDROID_LINT_NULLNESS_IGNORE_DEPRECATED=true`
if you want lint to ignore classes and members that have been annotated with
`@Deprecated`."
+ url="https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+ urls="https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
+ errorLine1=" public static void confirmCustomAndroidXChecksRun(ConcurrentHashMap m) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="$SUPPORT/lint-checks/integration-tests/src/main/java/Sample.java"
+ line="37"
+ column="55"/>
+ </issue>
+
+</issues>
diff --git a/lint-checks/integration-tests/src/main/AndroidManifest.xml b/lint-checks/integration-tests/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..1a39913
--- /dev/null
+++ b/lint-checks/integration-tests/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest package="androidx.lint.integration.tests" />
diff --git a/lint-checks/integration-tests/src/main/java/Sample.java b/lint-checks/integration-tests/src/main/java/Sample.java
new file mode 100644
index 0000000..5d2ba27
--- /dev/null
+++ b/lint-checks/integration-tests/src/main/java/Sample.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class Sample {
+
+ /**
+ * This function does not specify the nullability of its return type.
+ * Lint should catch this and report an error.
+ * If Lint does not catch this, then Lint's intrinsic checks are not running
+ */
+ public static Sample confirmIntrinisicLintChecksRun() {
+ return null;
+ }
+
+ /**
+ * This function uses a disallowed annotation
+ * Lint should catch this and report an error.
+ * If Lint does not catch this, then our AndroidX-specific checks are not running
+ */
+ public static void confirmCustomAndroidXChecksRun(ConcurrentHashMap m) {
+ }
+
+ private Sample() {
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index d133174..326b1cd 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -383,6 +383,7 @@
includeProject(":lifecycle:lifecycle-viewmodel-ktx", "lifecycle/lifecycle-viewmodel-ktx", [BuildType.MAIN, BuildType.FLAN])
includeProject(":lifecycle:lifecycle-viewmodel-savedstate", "lifecycle/lifecycle-viewmodel-savedstate", [BuildType.MAIN, BuildType.FLAN])
includeProject(":lint-checks", "lint-checks")
+includeProject(":lint-checks:integration-tests", "lint-checks/integration-tests", [BuildType.COMPOSE])
includeProject(":lint-checks:tests", "lint-checks/tests", [BuildType.MAIN])
includeProject(":lint-demos:lint-demo-appcompat", "lint-demos/lint-demo-appcompat", [BuildType.MAIN])
includeProject(":loader:loader", "loader/loader", [BuildType.MAIN])