Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions examples/simple-android/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rules.android.lint.examples">
package="com.rules.android.lint">

<uses-sdk android:minSdkVersion="23"/>
<uses-sdk android:minSdkVersion="23" />

<application>
<activity
android:name=".TestActivity"
android:exported="true" />
</application>

</manifest>
36 changes: 32 additions & 4 deletions examples/simple-android/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,25 +1,53 @@
load("@rules_android//android:rules.bzl", "android_library")
load("@rules_android//android:rules.bzl", "android_binary", "android_library")
load("@rules_android_lint//rules:defs.bzl", "android_lint", "android_lint_test")
load("@rules_android_lint//toolchains:toolchain.bzl", "android_lint_toolchain")

android_library(
name = "lib",
srcs = ["Foo.java"],
srcs = ["TestActivity.java"],
custom_package = "com.rules.android.lint.examples",
manifest = "LibManifest.xml",
)

android_binary(
name = "bin",
srcs = ["Foo.java"],
custom_package = "com.rules.android.lint",
manifest = "AndroidManifest.xml",
deps = [
":lib",
],
)

android_lint(
name = "lib_lint",
srcs = ["Foo.java"],
srcs = ["TestActivity.java"],
android_lint_config = "lint.xml",
lib = ":lib",
manifest = "LibManifest.xml",
)

android_lint_test(
name = "lib_lint_test",
srcs = ["Foo.java"],
srcs = ["TestActivity.java"],
baseline = "lib_lint_test_lint_baseline.xml",
lib = ":lib",
manifest = "LibManifest.xml",
)

android_lint(
name = "bin_lint",
srcs = ["Foo.java"],
android_lint_config = "lint.xml",
lib = ":bin",
manifest = "AndroidManifest.xml",
)

android_lint_test(
name = "bin_lint_test",
srcs = ["Foo.java"],
baseline = "bin_lint_test_lint_baseline.xml",
lib = ":bin",
)

android_lint_toolchain(
Expand Down
7 changes: 7 additions & 0 deletions examples/simple-android/LibManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rules.android.lint.examples">

<uses-sdk android:minSdkVersion="1"
android:targetSdkVersion="1" />
</manifest>
7 changes: 7 additions & 0 deletions examples/simple-android/TestActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.rules.android.lint;

import android.app.Activity;

public class TestActivity extends Activity {

}
5 changes: 5 additions & 0 deletions examples/simple-android/WORKSPACE.bzlmod
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
android_sdk_repository(name = "androidsdk")

android_ndk_repository(
name = "androidndk",
api_level = 30,
)
15 changes: 15 additions & 0 deletions examples/simple-android/bin_lint_test_lint_baseline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.3.0-alpha09" type="baseline" client="" dependencies="false" name="" variant="all" version="8.3.0-alpha09">

<issue
id="DefaultLocale"
message="Implicitly using the default locale is a common source of bugs: Use `toUpperCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
errorLine1=" System.out.println(&quot;WRONG&quot;.toUpperCase());"
errorLine2=" ~~~~~~~~~~~">
<location
file="Foo.java"
line="6"
column="32"/>
</issue>

</issues>s
23 changes: 8 additions & 15 deletions examples/simple-android/lib_lint_test_lint_baseline.xml
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.3.0-alpha09">
<issues format="6" by="lint 8.3.0-alpha09" type="baseline" client="" dependencies="false" name="" variant="all" version="8.3.0-alpha09">

<issue
id="DefaultLocale"
severity="Error"
message="Implicitly using the default locale is a common source of bugs: Use `toUpperCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
category="Correctness"
priority="6"
summary="Implied default locale in case conversion"
explanation="Calling `String#toLowerCase()` or `#toUpperCase()` **without specifying an explicit locale** is a common source of bugs. The reason for that is that those methods will use the current locale on the user&apos;s device, and even though the code appears to work correctly when you are developing the app, it will fail in some locales. For example, in the Turkish locale, the uppercase replacement for `i` is **not** `I`.&#xA;&#xA;If you want the methods to just perform ASCII replacement, for example to convert an enum name, call `String#toUpperCase(Locale.US)` instead. If you really want to use the current locale, call `String#toUpperCase(Locale.getDefault())` instead."
url="https://developer.android.com/reference/java/util/Locale.html#default_locale"
urls="https://developer.android.com/reference/java/util/Locale.html#default_locale"
errorLine1=" System.out.println(&quot;WRONG&quot;.toUpperCase());"
errorLine2=" ~~~~~~~~~~~">
id="ExpiredTargetSdkVersion"
message="Google Play requires that apps target API level 33 or higher."
errorLine1=" android:targetSdkVersion=&quot;1&quot; />"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="Foo.java"
file="LibManifest.xml"
line="6"
column="32"/>
column="9"/>
</issue>

</issues>
</issues>
13 changes: 10 additions & 3 deletions rules/impl.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def _run_android_lint(
deps,
resource_files,
manifest,
merged_manifest,
compile_sdk_version,
java_language_level,
kotlin_language_level,
Expand All @@ -48,6 +49,7 @@ def _run_android_lint(
deps: Depset of aars and jars to include on the classpath
resource_files: The Android resource files
manifest: The Android manifest file
merged_manifest: The Android merged manifest file (only for android_binary targets)
compile_sdk_version: The Android compile SDK version
java_language_level: The Java language level
kotlin_language_level: The Kotlin language level
Expand Down Expand Up @@ -87,6 +89,9 @@ def _run_android_lint(
if manifest:
args.add("--android-manifest", manifest)
inputs.append(manifest)
if merged_manifest:
args.add("--android-merged-manifest", merged_manifest)
inputs.append(merged_manifest)
if not regenerate and baseline:
args.add("--baseline-file", baseline)
inputs.append(baseline)
Expand Down Expand Up @@ -169,9 +174,10 @@ def process_android_lint_issues(ctx, regenerate):
# Append the Android manifest file. Lint requires that the input manifest files be named
# exactly `AndroidManifest.xml`.
manifest = ctx.file.manifest
if manifest and manifest.basename != "AndroidManifest.xml":
Copy link
Contributor Author

@arunkumar9t2 arunkumar9t2 Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint does seem to work when we pass the file as-is - here it is passed as LibManifest.xml and baseline does report issues. Please let me know if there is any case I missed.

manifest = ctx.actions.declare_file("AndroidManifest.xml")
ctx.actions.symlink(output = manifest, target_file = ctx.file.manifest)

merged_manifest = None
if ctx.attr.lib and AndroidManifestInfo in ctx.attr.lib and AndroidBinaryData in ctx.attr.lib:
merged_manifest = ctx.attr.lib[AndroidManifestInfo].manifest

# Collect the transitive classpath jars to run lint against.
deps = []
Expand Down Expand Up @@ -207,6 +213,7 @@ def process_android_lint_issues(ctx, regenerate):
deps = depset(transitive = deps),
resource_files = ctx.files.resource_files,
manifest = manifest,
merged_manifest = merged_manifest,
compile_sdk_version = _utils.get_android_lint_toolchain(ctx).compile_sdk_version,
java_language_level = _utils.get_android_lint_toolchain(ctx).java_language_level,
kotlin_language_level = _utils.get_android_lint_toolchain(ctx).kotlin_language_level,
Expand Down
6 changes: 6 additions & 0 deletions src/cli/AndroidLintActionArgs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ internal class AndroidLintActionArgs(
transform = argsParserPathTransformer,
).default { null }

val androidMergedManifest: Path? by parser.storing(
names = arrayOf("--android-merged-manifest"),
help = "Merged android manifest for Android Binary targets",
transform = argsParserPathTransformer,
).default { null }

val baselineFile: Path? by parser.storing(
names = arrayOf("--baseline-file"),
help = "",
Expand Down
7 changes: 7 additions & 0 deletions src/cli/AndroidLintProject.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal fun createProjectXMLString(
srcs: List<Path>,
resources: List<Path>,
androidManifest: Path?,
androidMergedManifest: Path?,
classpathJars: List<Path>,
classpathAars: List<Path>,
classpathExtractedAarDirectories: List<Pair<Path, Path>>,
Expand Down Expand Up @@ -64,6 +65,12 @@ internal fun createProjectXMLString(
moduleElement.appendChild(element)
}

if (androidMergedManifest != null) {
val element = document.createElement("merged-manifest")
element.setAttribute("file", androidMergedManifest.pathString)
moduleElement.appendChild(element)
}

classpathJars.forEach { jar ->
val element = document.createElement("classpath")
element.setAttribute("jar", jar.absolutePathString())
Expand Down
1 change: 1 addition & 0 deletions src/cli/AndroidLintRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ internal class AndroidLintRunner {
srcs = args.srcs.sortedDescending(),
resources = args.resources.sortedDescending(),
androidManifest = args.androidManifest,
androidMergedManifest = args.androidMergedManifest,
classpathJars = jars.sortedDescending(),
classpathAars = emptyList(),
classpathExtractedAarDirectories = unpackedAars,
Expand Down
5 changes: 5 additions & 0 deletions tests/src/cli/AndroidLintActionArgsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class AndroidLintActionArgsTest {
"path/to/resource/strings.xml",
"--android-manifest",
"AndroidManifest.xml",
"--android-merged-manifest",
"processed/AndroidManifest.xml",
"--baseline-file",
"lib_lint_baseline.xml",
"--config-file",
Expand Down Expand Up @@ -70,5 +72,8 @@ class AndroidLintActionArgsTest {
assertThat(parseArgs.javaLanguageLevel).isEqualTo("1.7")
assertThat(parseArgs.kotlinLanguageLevel).isEqualTo("1.8")
assertThat(parseArgs.enableCheckDependencies).isTrue()
assertThat(parseArgs.androidManifest).isEqualTo(Paths.get("AndroidManifest.xml"))
assertThat(parseArgs.androidMergedManifest)
.isEqualTo(Paths.get("processed/AndroidManifest.xml"))
}
}
5 changes: 4 additions & 1 deletion tests/src/cli/AndroidLintProjectTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ class AndroidLintProjectTest {

@Test
fun `test asXMLString does produce correct project file content`() {
val manifest = tmpDirectory.newPath("AndroidManifest.xml")
assertThat(
createProjectXMLString(
moduleName = "test_module_name",
rootDir = tmpDirectory.root.absolutePath,
srcs = listOf(tmpDirectory.newPath("Foo.kt")),
resources = listOf(tmpDirectory.newPath("foo.xml")),
androidManifest = tmpDirectory.newPath("AndroidManifest.xml"),
androidManifest = manifest,
classpathJars = listOf(tmpDirectory.newPath("Foo.jar")),
classpathAars = listOf(tmpDirectory.newPath("Foo.aar")),
classpathExtractedAarDirectories = listOf(
Expand All @@ -35,6 +36,7 @@ class AndroidLintProjectTest {
),
),
customLintChecks = listOf(tmpDirectory.newPath("tmp/unpacked_aars/bar/lint.jar")),
androidMergedManifest = manifest,
),
).isEqualTo(
"""
Expand All @@ -45,6 +47,7 @@ class AndroidLintProjectTest {
<src file="{root}/Foo.kt"/>
<resource file="{root}/foo.xml"/>
<manifest file="{root}/AndroidManifest.xml"/>
<merged-manifest file="{root}/AndroidManifest.xml"/>
<classpath jar="{root}/Foo.jar"/>
<aar file="{root}/Foo.aar"/>
<aar extracted="{root}/tmp/unpacked_aars/bar" file="{root}/Bar.aar"/>
Expand Down