Android linter
What is a linter?
A linter is a static code analyzer that helps identify well-known issues and potential improvements in your code. It goes beyond what a compiler does by ensuring proper usage of the language and adherence to best practices. While a compiler validates code against a grammar, a linter focuses on code quality and architecture.
Having no complaints from a linter doesn't mean everything is perfect. A review from another developer is still necessary to double-check.
Why use a linter?
Using a linter ensures:
- Consistency: Enforces a standard code style, similar to our codestyle.
- Focus: Allows reviewers to focus on logic rather than formatting or trivial issues.
- Prevention: Helps avoid crashes and bugs by catching common mistakes, such as using APIs not supported by the target Android API level.
For example, failing to check the Android API version before using an unsupported API can lead to crashes.
Linters used in the project
KTLint
We use KTLint as our Kotlin linter, integrated via Gradle plugin. The configuration is located in the main build.gradle.kts
file. We mostly use the default configuration but enable SARIF reports for GitHub Actions to annotate issues in pull requests.
Ignoring an issue
Always try to fix issues rather than ignoring them. If ignoring is necessary, follow these steps:
-
Use the
@Suppress
annotation for specific constructs:@Suppress("trailing-comma-on-call-site")
fun myCallSiteExample() {
myFunction(
"value1",
"value2", // This trailing comma would normally cause a warning
)
} -
For project-wide suppression, update the
.editorconfig
file as per this guide. Open a dedicated PR with an explanation for disabling the rule:...
# Allow trailing commas but do not enfoce it to follow Kotlin convention
ktlint_standard_trailing-comma-on-call-site = disabled
ij_kotlin_allow_trailing_comma_on_call_site = true
ktlint_standard_trailing-comma-on-declaration-site = disabled
ij_kotlin_allow_trailing_comma = true
Running KTLint locally
Run the following command to check all code in the repository:
./gradlew ktlintCheck :build-logic:convention:ktlintCheck --continue
Use --continue
to get all issues across Gradle modules instead of stopping at the first failure.
You can add this check to be run automatically through a git pre-commit hook by running this command
./gradlew addKtlintCheckGitPreCommitHook
Android Linter
The Android linter is enabled for all variants to ensure comprehensive checks. Its configuration is located in build-logic/convention/src/main/kotlin/AndroidCommonConventionPlugin.kt
. SARIF reports are generated for GitHub Actions to annotate issues in pull requests.
Ignoring an issue
Follow these steps to ignore an issue:
- Use the
@Suppress
annotation for specific constructs. - Add the issue to the
lint-baseline.xml
file. (See how to) - Disable the issue in the lint settings directly.
If you disable an issue, open a dedicated PR with an explanation.
Running the Android linter locally
Run the following command:
./gradlew lintDebug --continue
Use --continue
to get all issues across Gradle modules instead of stopping at the first failure.
Managing lint rules
Changing the lint level of an issue
The Android linter comes with predefined rules bundled into the Android Gradle plugin. Some libraries, like Timber, also provide custom lint rules.
To change the severity of a rule, update the Gradle configuration in build-logic/convention/src/main/kotlin/AndroidCommonConventionPlugin.kt
:
lint {
...
disable += "MissingTranslation"
error += "LogNotTimber"
}
LogNotTimber
: Promoted from a warning to an error to enforce the usage of Timber instead of the classic logger.MissingTranslation
: Disabled because translations are added only during CI release builds.
Changes to lint levels should be made in a PR with a clear explanation.
Baseline management
What is a baseline?
The baseline is an XML file (lint-baseline.xml
) in each Gradle module that lists ignored errors. It was created when the linter was first enabled to avoid fixing hundreds of pre-existing issues.
A great first contribution is to remove issues from the baseline by fixing them.
Updating the baseline
When updating the Android Gradle Plugin, new lint issues may arise, or existing ones may change. To regenerate the baseline:
./gradlew updateLintBaseline
After updating, review the ignored errors to determine if they should be addressed now or later. Open a GitHub PR or issue as needed.
Extending lint rules
We encourage you to propose new linter rules specific to our project. These rules can help identify misuse of APIs or enforce design patterns.
Tips for contributors
- Fix lint issues rather than ignoring them whenever possible.
- Provide clear explanations in PRs for any changes to lint configurations or baselines.
- Use the linter locally to catch issues early and save CI resources.
Happy linting! 🚀