2020-06-03 05:09:13 +02:00
// Copyright 2020 Google Inc. All rights reserved.
//
// 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 java
import (
"fmt"
"sort"
2020-07-17 02:32:17 +02:00
"strings"
2020-06-03 05:09:13 +02:00
2021-02-15 16:41:33 +01:00
"github.com/google/blueprint/proptools"
2020-06-03 05:09:13 +02:00
"android/soong/android"
2021-03-04 19:44:12 +01:00
"android/soong/java/config"
"android/soong/remoteexec"
2020-06-03 05:09:13 +02:00
)
2021-04-21 23:01:55 +02:00
// lint checks automatically enforced for modules that have different min_sdk_version than
// sdk_version
var updatabilityChecks = [ ] string { "NewApi" }
2020-06-03 05:09:13 +02:00
type LintProperties struct {
// Controls for running Android Lint on the module.
Lint struct {
// If true, run Android Lint on the module. Defaults to true.
Enabled * bool
// Flags to pass to the Android Lint tool.
Flags [ ] string
// Checks that should be treated as fatal.
Fatal_checks [ ] string
// Checks that should be treated as errors.
Error_checks [ ] string
// Checks that should be treated as warnings.
Warning_checks [ ] string
// Checks that should be skipped.
Disabled_checks [ ] string
2020-06-19 00:56:48 +02:00
// Modules that provide extra lint checks
Extra_check_modules [ ] string
2021-02-15 16:41:33 +01:00
2024-01-04 19:29:27 +01:00
// The lint baseline file to use. If specified, lint warnings listed in this file will be
// suppressed during lint checks.
2021-02-15 16:41:33 +01:00
Baseline_filename * string
2021-04-22 01:17:25 +02:00
// If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
Strict_updatability_linting * bool
2022-08-11 20:59:04 +02:00
// Treat the code in this module as test code for @VisibleForTesting enforcement.
// This will be true by default for test module types, false otherwise.
// If soong gets support for testonly, this flag should be replaced with that.
Test * bool
2023-09-29 02:21:56 +02:00
// Whether to ignore the exit code of Android lint. This is the --exit_code
// option. Defaults to false.
Suppress_exit_code * bool
2020-06-03 05:09:13 +02:00
}
}
type linter struct {
2021-02-25 17:23:22 +01:00
name string
manifest android . Path
mergedManifest android . Path
srcs android . Paths
srcJars android . Paths
resources android . Paths
classpath android . Paths
classes android . Path
extraLintCheckJars android . Paths
library bool
2023-11-06 20:43:17 +01:00
minSdkVersion android . ApiLevel
targetSdkVersion android . ApiLevel
compileSdkVersion android . ApiLevel
2021-06-08 20:11:21 +02:00
compileSdkKind android . SdkKind
2021-02-25 17:23:22 +01:00
javaLanguageLevel string
kotlinLanguageLevel string
outputs lintOutputs
properties LintProperties
extraMainlineLintErrors [ ] string
2023-12-08 21:27:24 +01:00
compile_data android . Paths
2020-07-03 20:56:24 +02:00
2020-07-22 05:31:17 +02:00
reports android . Paths
2020-07-03 20:56:24 +02:00
buildModuleReportZip bool
2020-06-03 05:09:13 +02:00
}
type lintOutputs struct {
2023-03-03 01:43:15 +01:00
html android . Path
text android . Path
xml android . Path
referenceBaseline android . Path
2020-07-03 20:56:24 +02:00
2020-07-22 05:31:17 +02:00
depSets LintDepSets
2020-07-03 20:56:24 +02:00
}
2020-07-22 05:31:17 +02:00
type lintOutputsIntf interface {
2020-07-03 20:56:24 +02:00
lintOutputs ( ) * lintOutputs
}
2022-01-14 22:19:14 +01:00
type LintDepSetsIntf interface {
2020-07-22 05:31:17 +02:00
LintDepSets ( ) LintDepSets
2021-05-11 00:30:00 +02:00
// Methods used to propagate strict_updatability_linting values.
2022-01-14 22:19:14 +01:00
GetStrictUpdatabilityLinting ( ) bool
SetStrictUpdatabilityLinting ( bool )
2020-07-22 05:31:17 +02:00
}
type LintDepSets struct {
2022-04-21 21:50:51 +02:00
HTML , Text , XML * android . DepSet [ android . Path ]
2020-07-22 05:31:17 +02:00
}
type LintDepSetsBuilder struct {
2022-04-21 21:50:51 +02:00
HTML , Text , XML * android . DepSetBuilder [ android . Path ]
2020-07-22 05:31:17 +02:00
}
func NewLintDepSetBuilder ( ) LintDepSetsBuilder {
return LintDepSetsBuilder {
2022-04-21 21:50:51 +02:00
HTML : android . NewDepSetBuilder [ android . Path ] ( android . POSTORDER ) ,
Text : android . NewDepSetBuilder [ android . Path ] ( android . POSTORDER ) ,
XML : android . NewDepSetBuilder [ android . Path ] ( android . POSTORDER ) ,
2020-07-22 05:31:17 +02:00
}
}
func ( l LintDepSetsBuilder ) Direct ( html , text , xml android . Path ) LintDepSetsBuilder {
l . HTML . Direct ( html )
l . Text . Direct ( text )
l . XML . Direct ( xml )
return l
}
func ( l LintDepSetsBuilder ) Transitive ( depSets LintDepSets ) LintDepSetsBuilder {
if depSets . HTML != nil {
l . HTML . Transitive ( depSets . HTML )
}
if depSets . Text != nil {
l . Text . Transitive ( depSets . Text )
}
if depSets . XML != nil {
l . XML . Transitive ( depSets . XML )
}
return l
}
func ( l LintDepSetsBuilder ) Build ( ) LintDepSets {
return LintDepSets {
HTML : l . HTML . Build ( ) ,
Text : l . Text . Build ( ) ,
XML : l . XML . Build ( ) ,
}
}
2023-02-01 00:49:07 +01:00
type lintDatabaseFiles struct {
apiVersionsModule string
apiVersionsCopiedName string
apiVersionsPrebuiltPath string
annotationsModule string
annotationCopiedName string
annotationPrebuiltpath string
}
var allLintDatabasefiles = map [ android . SdkKind ] lintDatabaseFiles {
android . SdkPublic : {
apiVersionsModule : "api_versions_public" ,
apiVersionsCopiedName : "api_versions_public.xml" ,
apiVersionsPrebuiltPath : "prebuilts/sdk/current/public/data/api-versions.xml" ,
annotationsModule : "sdk-annotations.zip" ,
annotationCopiedName : "annotations-public.zip" ,
annotationPrebuiltpath : "prebuilts/sdk/current/public/data/annotations.zip" ,
} ,
android . SdkSystem : {
apiVersionsModule : "api_versions_system" ,
apiVersionsCopiedName : "api_versions_system.xml" ,
apiVersionsPrebuiltPath : "prebuilts/sdk/current/system/data/api-versions.xml" ,
annotationsModule : "sdk-annotations-system.zip" ,
annotationCopiedName : "annotations-system.zip" ,
annotationPrebuiltpath : "prebuilts/sdk/current/system/data/annotations.zip" ,
} ,
android . SdkModule : {
apiVersionsModule : "api_versions_module_lib" ,
apiVersionsCopiedName : "api_versions_module_lib.xml" ,
apiVersionsPrebuiltPath : "prebuilts/sdk/current/module-lib/data/api-versions.xml" ,
annotationsModule : "sdk-annotations-module-lib.zip" ,
annotationCopiedName : "annotations-module-lib.zip" ,
annotationPrebuiltpath : "prebuilts/sdk/current/module-lib/data/annotations.zip" ,
} ,
android . SdkSystemServer : {
apiVersionsModule : "api_versions_system_server" ,
apiVersionsCopiedName : "api_versions_system_server.xml" ,
apiVersionsPrebuiltPath : "prebuilts/sdk/current/system-server/data/api-versions.xml" ,
annotationsModule : "sdk-annotations-system-server.zip" ,
annotationCopiedName : "annotations-system-server.zip" ,
annotationPrebuiltpath : "prebuilts/sdk/current/system-server/data/annotations.zip" ,
} ,
}
2020-07-22 05:31:17 +02:00
func ( l * linter ) LintDepSets ( ) LintDepSets {
return l . outputs . depSets
}
2022-01-14 22:19:14 +01:00
func ( l * linter ) GetStrictUpdatabilityLinting ( ) bool {
2021-05-11 00:30:00 +02:00
return BoolDefault ( l . properties . Lint . Strict_updatability_linting , false )
}
2022-01-14 22:19:14 +01:00
func ( l * linter ) SetStrictUpdatabilityLinting ( strictLinting bool ) {
2021-05-11 00:30:00 +02:00
l . properties . Lint . Strict_updatability_linting = & strictLinting
}
2022-01-14 22:19:14 +01:00
var _ LintDepSetsIntf = ( * linter ) ( nil )
2020-07-22 05:31:17 +02:00
var _ lintOutputsIntf = ( * linter ) ( nil )
2020-07-03 20:56:24 +02:00
func ( l * linter ) lintOutputs ( ) * lintOutputs {
return & l . outputs
2020-06-03 05:09:13 +02:00
}
func ( l * linter ) enabled ( ) bool {
return BoolDefault ( l . properties . Lint . Enabled , true )
}
2020-06-19 00:56:48 +02:00
func ( l * linter ) deps ( ctx android . BottomUpMutatorContext ) {
if ! l . enabled ( ) {
return
}
2020-07-17 02:32:17 +02:00
extraCheckModules := l . properties . Lint . Extra_check_modules
2022-11-18 19:20:20 +01:00
if extraCheckModulesEnv := ctx . Config ( ) . Getenv ( "ANDROID_LINT_CHECK_EXTRA_MODULES" ) ; extraCheckModulesEnv != "" {
extraCheckModules = append ( extraCheckModules , strings . Split ( extraCheckModulesEnv , "," ) ... )
2020-07-17 02:32:17 +02:00
}
ctx . AddFarVariationDependencies ( ctx . Config ( ) . BuildOSCommonTarget . Variations ( ) ,
extraLintCheckTag , extraCheckModules ... )
2020-06-19 00:56:48 +02:00
}
2021-03-10 18:45:40 +01:00
// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
// around.
2021-03-04 19:44:12 +01:00
type lintPaths struct {
projectXML android . WritablePath
configXML android . WritablePath
cacheDir android . WritablePath
homeDir android . WritablePath
srcjarDir android . WritablePath
}
2021-03-10 19:40:58 +01:00
func lintRBEExecStrategy ( ctx android . ModuleContext ) string {
return ctx . Config ( ) . GetenvWithDefault ( "RBE_LINT_EXEC_STRATEGY" , remoteexec . LocalExecStrategy )
}
2022-08-13 01:09:24 +02:00
func ( l * linter ) writeLintProjectXML ( ctx android . ModuleContext , rule * android . RuleBuilder , srcsList android . Path ) lintPaths {
2021-03-04 19:44:12 +01:00
projectXMLPath := android . PathForModuleOut ( ctx , "lint" , "project.xml" )
2020-06-03 05:09:13 +02:00
// Lint looks for a lint.xml file next to the project.xml file, give it one.
2021-03-04 19:44:12 +01:00
configXMLPath := android . PathForModuleOut ( ctx , "lint" , "lint.xml" )
cacheDir := android . PathForModuleOut ( ctx , "lint" , "cache" )
homeDir := android . PathForModuleOut ( ctx , "lint" , "home" )
2020-06-03 05:09:13 +02:00
2021-03-13 02:56:51 +01:00
srcJarDir := android . PathForModuleOut ( ctx , "lint" , "srcjars" )
2020-06-03 05:09:13 +02:00
srcJarList := zipSyncCmd ( ctx , rule , srcJarDir , l . srcJars )
cmd := rule . Command ( ) .
2021-04-20 02:58:22 +02:00
BuiltTool ( "lint_project_xml" ) .
2020-06-03 05:09:13 +02:00
FlagWithOutput ( "--project_out " , projectXMLPath ) .
FlagWithOutput ( "--config_out " , configXMLPath ) .
FlagWithArg ( "--name " , ctx . ModuleName ( ) )
if l . library {
cmd . Flag ( "--library" )
}
2022-08-11 20:59:04 +02:00
if proptools . BoolDefault ( l . properties . Lint . Test , false ) {
2020-06-03 05:09:13 +02:00
cmd . Flag ( "--test" )
}
if l . manifest != nil {
2021-03-24 01:07:14 +01:00
cmd . FlagWithInput ( "--manifest " , l . manifest )
2020-06-03 05:09:13 +02:00
}
if l . mergedManifest != nil {
2021-03-24 01:07:14 +01:00
cmd . FlagWithInput ( "--merged_manifest " , l . mergedManifest )
2020-06-03 05:09:13 +02:00
}
2021-03-24 01:07:14 +01:00
// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
// lint separately.
2022-08-13 01:09:24 +02:00
cmd . FlagWithInput ( "--srcs " , srcsList )
2020-06-03 05:09:13 +02:00
cmd . FlagWithInput ( "--generated_srcs " , srcJarList )
2021-03-24 01:07:14 +01:00
if len ( l . resources ) > 0 {
resourcesList := android . PathForModuleOut ( ctx , "lint-resources.list" )
cmd . FlagWithRspFileInputList ( "--resources " , resourcesList , l . resources )
2020-06-03 05:09:13 +02:00
}
if l . classes != nil {
2021-03-24 01:07:14 +01:00
cmd . FlagWithInput ( "--classes " , l . classes )
2020-06-03 05:09:13 +02:00
}
2021-03-24 01:07:14 +01:00
cmd . FlagForEachInput ( "--classpath " , l . classpath )
2020-06-03 05:09:13 +02:00
2021-03-24 01:07:14 +01:00
cmd . FlagForEachInput ( "--extra_checks_jar " , l . extraLintCheckJars )
2020-06-03 05:09:13 +02:00
2021-03-13 02:56:51 +01:00
cmd . FlagWithArg ( "--root_dir " , "$PWD" )
2020-06-23 19:25:26 +02:00
// The cache tag in project.xml is relative to the root dir, or the project.xml file if
// the root dir is not set.
cmd . FlagWithArg ( "--cache_dir " , cacheDir . String ( ) )
2020-06-03 05:09:13 +02:00
cmd . FlagWithInput ( "@" ,
android . PathForSource ( ctx , "build/soong/java/lint_defaults.txt" ) )
2023-02-01 00:49:07 +01:00
if l . compileSdkKind == android . SdkPublic {
cmd . FlagForEachArg ( "--error_check " , l . extraMainlineLintErrors )
} else {
// TODO(b/268261262): Remove this branch. We're demoting NewApi to a warning due to pre-existing issues that need to be fixed.
cmd . FlagForEachArg ( "--warning_check " , l . extraMainlineLintErrors )
}
2020-06-03 05:09:13 +02:00
cmd . FlagForEachArg ( "--disable_check " , l . properties . Lint . Disabled_checks )
cmd . FlagForEachArg ( "--warning_check " , l . properties . Lint . Warning_checks )
cmd . FlagForEachArg ( "--error_check " , l . properties . Lint . Error_checks )
cmd . FlagForEachArg ( "--fatal_check " , l . properties . Lint . Fatal_checks )
2023-02-27 06:15:25 +01:00
// TODO(b/193460475): Re-enable strict updatability linting
//if l.GetStrictUpdatabilityLinting() {
// // Verify the module does not baseline issues that endanger safe updatability.
// if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
// cmd.FlagWithInput("--baseline ", baselinePath.Path())
// cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
// }
//}
2021-04-22 01:17:25 +02:00
2021-03-04 19:44:12 +01:00
return lintPaths {
projectXML : projectXMLPath ,
configXML : configXMLPath ,
cacheDir : cacheDir ,
homeDir : homeDir ,
}
2020-06-03 05:09:13 +02:00
}
2020-07-28 20:32:07 +02:00
// generateManifest adds a command to the rule to write a simple manifest that contains the
2020-06-03 05:09:13 +02:00
// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
2021-03-13 02:56:51 +01:00
func ( l * linter ) generateManifest ( ctx android . ModuleContext , rule * android . RuleBuilder ) android . WritablePath {
2020-06-03 05:09:13 +02:00
manifestPath := android . PathForModuleOut ( ctx , "lint" , "AndroidManifest.xml" )
rule . Command ( ) . Text ( "(" ) .
Text ( ` echo "<?xml version='1.0' encoding='utf-8'?>" && ` ) .
Text ( ` echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" && ` ) .
Text ( ` echo " android:versionCode='1' android:versionName='1' >" && ` ) .
2023-11-06 20:43:17 +01:00
Textf ( ` echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" && ` ,
l . minSdkVersion . String ( ) , l . targetSdkVersion . String ( ) ) .
2020-06-03 05:09:13 +02:00
Text ( ` echo "</manifest>" ` ) .
Text ( ") >" ) . Output ( manifestPath )
return manifestPath
}
func ( l * linter ) lint ( ctx android . ModuleContext ) {
if ! l . enabled ( ) {
return
}
2024-01-29 22:49:14 +01:00
for _ , flag := range l . properties . Lint . Flags {
if strings . Contains ( flag , "--disable" ) || strings . Contains ( flag , "--enable" ) || strings . Contains ( flag , "--check" ) {
ctx . PropertyErrorf ( "lint.flags" , "Don't use --disable, --enable, or --check in the flags field, instead use the dedicated disabled_checks, warning_checks, error_checks, or fatal_checks fields" )
}
}
2023-11-06 20:43:17 +01:00
if l . minSdkVersion . CompareTo ( l . compileSdkVersion ) == - 1 {
2021-04-21 23:01:55 +02:00
l . extraMainlineLintErrors = append ( l . extraMainlineLintErrors , updatabilityChecks ... )
2022-08-15 21:23:38 +02:00
// Skip lint warning checks for NewApi warnings for libcore where they come from source
// files that reference the API they are adding (b/208656169).
2022-10-25 17:45:14 +02:00
if ! strings . HasPrefix ( ctx . ModuleDir ( ) , "libcore" ) {
2022-08-15 21:23:38 +02:00
_ , filtered := android . FilterList ( l . properties . Lint . Warning_checks , updatabilityChecks )
if len ( filtered ) != 0 {
ctx . PropertyErrorf ( "lint.warning_checks" ,
"Can't treat %v checks as warnings if min_sdk_version is different from sdk_version." , filtered )
}
2021-04-21 23:01:55 +02:00
}
2022-08-15 21:23:38 +02:00
_ , filtered := android . FilterList ( l . properties . Lint . Disabled_checks , updatabilityChecks )
2021-04-21 23:01:55 +02:00
if len ( filtered ) != 0 {
ctx . PropertyErrorf ( "lint.disabled_checks" ,
"Can't disable %v checks if min_sdk_version is different from sdk_version." , filtered )
}
2022-06-29 23:58:03 +02:00
// TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
if ctx . ModuleName ( ) == "PermissionController" {
l . extraMainlineLintErrors = android . FilterListPred ( l . extraMainlineLintErrors , func ( s string ) bool {
return s != "NewApi"
} )
l . properties . Lint . Warning_checks = append ( l . properties . Lint . Warning_checks , "NewApi" )
}
2021-02-25 17:23:22 +01:00
}
2020-06-19 00:56:48 +02:00
extraLintCheckModules := ctx . GetDirectDepsWithTag ( extraLintCheckTag )
for _ , extraLintCheckModule := range extraLintCheckModules {
2023-12-13 22:47:44 +01:00
if dep , ok := android . OtherModuleProvider ( ctx , extraLintCheckModule , JavaInfoProvider ) ; ok {
2021-02-01 22:59:03 +01:00
l . extraLintCheckJars = append ( l . extraLintCheckJars , dep . ImplementationAndResourcesJars ... )
2020-06-19 00:56:48 +02:00
} else {
ctx . PropertyErrorf ( "lint.extra_check_modules" ,
"%s is not a java module" , ctx . OtherModuleName ( extraLintCheckModule ) )
}
}
2022-11-29 21:16:36 +01:00
l . extraLintCheckJars = append ( l . extraLintCheckJars , android . PathForSource ( ctx ,
"prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar" ) )
2021-03-13 02:56:51 +01:00
rule := android . NewRuleBuilder ( pctx , ctx ) .
Sbox ( android . PathForModuleOut ( ctx , "lint" ) ,
android . PathForModuleOut ( ctx , "lint.sbox.textproto" ) ) .
SandboxInputs ( )
if ctx . Config ( ) . UseRBE ( ) && ctx . Config ( ) . IsEnvTrue ( "RBE_LINT" ) {
pool := ctx . Config ( ) . GetenvWithDefault ( "RBE_LINT_POOL" , "java16" )
rule . Remoteable ( android . RemoteRuleSupports { RBE : true } )
rule . Rewrapper ( & remoteexec . REParams {
Labels : map [ string ] string { "type" : "tool" , "name" : "lint" } ,
ExecStrategy : lintRBEExecStrategy ( ctx ) ,
ToolchainInputs : [ ] string { config . JavaCmd ( ctx ) . String ( ) } ,
2021-06-09 21:48:53 +02:00
Platform : map [ string ] string { remoteexec . PoolKey : pool } ,
2021-03-13 02:56:51 +01:00
} )
}
2020-06-03 05:09:13 +02:00
if l . manifest == nil {
manifest := l . generateManifest ( ctx , rule )
l . manifest = manifest
2021-03-13 02:56:51 +01:00
rule . Temporary ( manifest )
2020-06-03 05:09:13 +02:00
}
2022-08-13 01:09:24 +02:00
srcsList := android . PathForModuleOut ( ctx , "lint" , "lint-srcs.list" )
srcsListRsp := android . PathForModuleOut ( ctx , "lint-srcs.list.rsp" )
2023-12-08 21:27:24 +01:00
rule . Command ( ) . Text ( "cp" ) . FlagWithRspFileInputList ( "" , srcsListRsp , l . srcs ) . Output ( srcsList ) . Implicits ( l . compile_data )
2022-08-13 01:09:24 +02:00
lintPaths := l . writeLintProjectXML ( ctx , rule , srcsList )
2020-06-03 05:09:13 +02:00
2021-03-13 02:56:51 +01:00
html := android . PathForModuleOut ( ctx , "lint" , "lint-report.html" )
text := android . PathForModuleOut ( ctx , "lint" , "lint-report.txt" )
xml := android . PathForModuleOut ( ctx , "lint" , "lint-report.xml" )
2023-03-03 01:43:15 +01:00
referenceBaseline := android . PathForModuleOut ( ctx , "lint" , "lint-baseline.xml" )
2020-07-03 20:56:24 +02:00
2020-07-22 05:31:17 +02:00
depSetsBuilder := NewLintDepSetBuilder ( ) . Direct ( html , text , xml )
2020-07-03 20:56:24 +02:00
ctx . VisitDirectDepsWithTag ( staticLibTag , func ( dep android . Module ) {
2022-01-14 22:19:14 +01:00
if depLint , ok := dep . ( LintDepSetsIntf ) ; ok {
2020-07-22 05:31:17 +02:00
depSetsBuilder . Transitive ( depLint . LintDepSets ( ) )
2020-07-03 20:56:24 +02:00
}
} )
2020-06-03 05:09:13 +02:00
2021-03-04 19:44:12 +01:00
rule . Command ( ) . Text ( "rm -rf" ) . Flag ( lintPaths . cacheDir . String ( ) ) . Flag ( lintPaths . homeDir . String ( ) )
rule . Command ( ) . Text ( "mkdir -p" ) . Flag ( lintPaths . cacheDir . String ( ) ) . Flag ( lintPaths . homeDir . String ( ) )
2021-03-04 19:01:34 +01:00
rule . Command ( ) . Text ( "rm -f" ) . Output ( html ) . Output ( text ) . Output ( xml )
2020-06-03 05:09:13 +02:00
2023-02-01 00:49:07 +01:00
files , ok := allLintDatabasefiles [ l . compileSdkKind ]
if ! ok {
files = allLintDatabasefiles [ android . SdkPublic ]
2021-06-08 20:11:21 +02:00
}
2020-07-06 20:45:51 +02:00
var annotationsZipPath , apiVersionsXMLPath android . Path
2020-07-07 18:09:23 +02:00
if ctx . Config ( ) . AlwaysUsePrebuiltSdks ( ) {
2023-02-01 00:49:07 +01:00
annotationsZipPath = android . PathForSource ( ctx , files . annotationPrebuiltpath )
apiVersionsXMLPath = android . PathForSource ( ctx , files . apiVersionsPrebuiltPath )
2020-07-06 20:45:51 +02:00
} else {
2023-02-01 00:49:07 +01:00
annotationsZipPath = copiedLintDatabaseFilesPath ( ctx , files . annotationCopiedName )
apiVersionsXMLPath = copiedLintDatabaseFilesPath ( ctx , files . apiVersionsCopiedName )
2020-07-06 20:45:51 +02:00
}
2021-03-04 19:44:12 +01:00
cmd := rule . Command ( )
2021-04-06 19:49:19 +02:00
cmd . Flag ( ` JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED" ` ) .
2021-03-04 19:44:12 +01:00
FlagWithArg ( "ANDROID_SDK_HOME=" , lintPaths . homeDir . String ( ) ) .
2020-07-06 20:45:51 +02:00
FlagWithInput ( "SDK_ANNOTATIONS=" , annotationsZipPath ) .
2021-03-04 19:44:12 +01:00
FlagWithInput ( "LINT_OPTS=-DLINT_API_DATABASE=" , apiVersionsXMLPath )
2021-03-13 02:56:51 +01:00
cmd . BuiltTool ( "lint" ) . ImplicitTool ( ctx . Config ( ) . HostJavaToolPath ( ctx , "lint.jar" ) ) .
2020-06-03 05:09:13 +02:00
Flag ( "--quiet" ) .
2023-12-07 22:57:28 +01:00
Flag ( "--include-aosp-issues" ) .
2021-03-04 19:44:12 +01:00
FlagWithInput ( "--project " , lintPaths . projectXML ) .
FlagWithInput ( "--config " , lintPaths . configXML ) .
2020-07-03 20:56:24 +02:00
FlagWithOutput ( "--html " , html ) .
FlagWithOutput ( "--text " , text ) .
FlagWithOutput ( "--xml " , xml ) .
2023-11-06 20:43:17 +01:00
FlagWithArg ( "--compile-sdk-version " , l . compileSdkVersion . String ( ) ) .
2020-06-03 05:09:13 +02:00
FlagWithArg ( "--java-language-level " , l . javaLanguageLevel ) .
FlagWithArg ( "--kotlin-language-level " , l . kotlinLanguageLevel ) .
FlagWithArg ( "--url " , fmt . Sprintf ( ".=.,%s=out" , android . PathForOutput ( ctx ) . String ( ) ) ) .
2022-08-13 01:09:24 +02:00
Flag ( "--apply-suggestions" ) . // applies suggested fixes to files in the sandbox
2020-06-03 05:09:13 +02:00
Flags ( l . properties . Lint . Flags ) .
2021-03-04 19:44:12 +01:00
Implicit ( annotationsZipPath ) .
2021-03-24 01:07:14 +01:00
Implicit ( apiVersionsXMLPath )
2020-07-17 02:32:17 +02:00
2021-03-13 02:56:51 +01:00
rule . Temporary ( lintPaths . projectXML )
rule . Temporary ( lintPaths . configXML )
2023-09-29 02:21:56 +02:00
suppressExitCode := BoolDefault ( l . properties . Lint . Suppress_exit_code , false )
if exitCode := ctx . Config ( ) . Getenv ( "ANDROID_LINT_SUPPRESS_EXIT_CODE" ) ; exitCode == "" && ! suppressExitCode {
2023-03-22 18:44:18 +01:00
cmd . Flag ( "--exitcode" )
}
2020-07-17 02:32:17 +02:00
if checkOnly := ctx . Config ( ) . Getenv ( "ANDROID_LINT_CHECK" ) ; checkOnly != "" {
cmd . FlagWithArg ( "--check " , checkOnly )
}
2024-01-04 19:29:27 +01:00
if l . properties . Lint . Baseline_filename != nil {
cmd . FlagWithInput ( "--baseline " , android . PathForModuleSrc ( ctx , * l . properties . Lint . Baseline_filename ) )
2021-02-15 16:41:33 +01:00
}
2023-03-03 01:43:15 +01:00
cmd . FlagWithOutput ( "--write-reference-baseline " , referenceBaseline )
2021-09-09 18:36:25 +02:00
2022-10-11 20:22:24 +02:00
cmd . Text ( "; EXITCODE=$?; " )
2021-04-06 03:38:05 +02:00
2022-08-13 01:09:24 +02:00
// The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
2022-10-11 20:22:24 +02:00
// export them out of the sandbox. Do this before exiting so that the suggestions exit even after
// a fatal error.
cmd . BuiltTool ( "soong_zip" ) .
2022-08-13 01:09:24 +02:00
FlagWithOutput ( "-o " , android . PathForModuleOut ( ctx , "lint" , "suggested-fixes.zip" ) ) .
FlagWithArg ( "-C " , cmd . PathForInput ( android . PathForSource ( ctx ) ) ) .
FlagWithInput ( "-r " , srcsList )
2022-10-11 20:22:24 +02:00
cmd . Text ( "; if [ $EXITCODE != 0 ]; then if [ -e" ) . Input ( text ) . Text ( "]; then cat" ) . Input ( text ) . Text ( "; fi; exit $EXITCODE; fi" )
rule . Command ( ) . Text ( "rm -rf" ) . Flag ( lintPaths . cacheDir . String ( ) ) . Flag ( lintPaths . homeDir . String ( ) )
// The HTML output contains a date, remove it to make the output deterministic.
rule . Command ( ) . Text ( ` sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|' ` ) . Output ( html )
2020-11-17 02:32:30 +01:00
rule . Build ( "lint" , "lint" )
2020-06-03 05:09:13 +02:00
2020-07-03 20:56:24 +02:00
l . outputs = lintOutputs {
2023-03-03 01:43:15 +01:00
html : html ,
text : text ,
xml : xml ,
referenceBaseline : referenceBaseline ,
2020-06-03 05:09:13 +02:00
2020-07-22 05:31:17 +02:00
depSets : depSetsBuilder . Build ( ) ,
2020-07-03 20:56:24 +02:00
}
2020-06-03 05:09:13 +02:00
2020-07-03 20:56:24 +02:00
if l . buildModuleReportZip {
2020-07-22 05:31:17 +02:00
l . reports = BuildModuleLintReportZips ( ctx , l . LintDepSets ( ) )
}
2024-01-05 21:51:25 +01:00
// Create a per-module phony target to run the lint check.
phonyName := ctx . ModuleName ( ) + "-lint"
ctx . Phony ( phonyName , xml )
2020-07-22 05:31:17 +02:00
}
2020-07-03 20:56:24 +02:00
2020-07-22 05:31:17 +02:00
func BuildModuleLintReportZips ( ctx android . ModuleContext , depSets LintDepSets ) android . Paths {
2022-04-21 21:50:51 +02:00
htmlList := android . SortedUniquePaths ( depSets . HTML . ToList ( ) )
textList := android . SortedUniquePaths ( depSets . Text . ToList ( ) )
xmlList := android . SortedUniquePaths ( depSets . XML . ToList ( ) )
2020-07-03 20:56:24 +02:00
2020-07-22 05:31:17 +02:00
if len ( htmlList ) == 0 && len ( textList ) == 0 && len ( xmlList ) == 0 {
return nil
2020-07-03 20:56:24 +02:00
}
2020-07-22 05:31:17 +02:00
htmlZip := android . PathForModuleOut ( ctx , "lint-report-html.zip" )
lintZip ( ctx , htmlList , htmlZip )
textZip := android . PathForModuleOut ( ctx , "lint-report-text.zip" )
lintZip ( ctx , textList , textZip )
xmlZip := android . PathForModuleOut ( ctx , "lint-report-xml.zip" )
lintZip ( ctx , xmlList , xmlZip )
return android . Paths { htmlZip , textZip , xmlZip }
2020-07-03 20:56:24 +02:00
}
2020-06-03 05:09:13 +02:00
type lintSingleton struct {
2023-03-03 01:43:15 +01:00
htmlZip android . WritablePath
textZip android . WritablePath
xmlZip android . WritablePath
referenceBaselineZip android . WritablePath
2020-06-03 05:09:13 +02:00
}
func ( l * lintSingleton ) GenerateBuildActions ( ctx android . SingletonContext ) {
l . generateLintReportZips ( ctx )
l . copyLintDependencies ( ctx )
}
2021-06-08 20:11:21 +02:00
func findModuleOrErr ( ctx android . SingletonContext , moduleName string ) android . Module {
var res android . Module
2020-06-03 05:09:13 +02:00
ctx . VisitAllModules ( func ( m android . Module ) {
2021-06-08 20:11:21 +02:00
if ctx . ModuleName ( m ) == moduleName {
if res == nil {
res = m
2020-06-03 05:09:13 +02:00
} else {
2021-06-08 20:11:21 +02:00
ctx . Errorf ( "lint: multiple %s modules found: %s and %s" , moduleName ,
ctx . ModuleSubDir ( m ) , ctx . ModuleSubDir ( res ) )
2020-06-03 05:09:13 +02:00
}
}
} )
2021-06-08 20:11:21 +02:00
return res
}
2020-06-03 05:09:13 +02:00
2021-06-08 20:11:21 +02:00
func ( l * lintSingleton ) copyLintDependencies ( ctx android . SingletonContext ) {
if ctx . Config ( ) . AlwaysUsePrebuiltSdks ( ) {
return
}
2023-02-01 00:49:07 +01:00
for _ , sdk := range android . SortedKeys ( allLintDatabasefiles ) {
files := allLintDatabasefiles [ sdk ]
apiVersionsDb := findModuleOrErr ( ctx , files . apiVersionsModule )
if apiVersionsDb == nil {
if ! ctx . Config ( ) . AllowMissingDependencies ( ) {
2024-05-02 13:44:20 +02:00
ctx . Errorf ( "lint: missing module %s" , files . apiVersionsModule )
2023-02-01 00:49:07 +01:00
}
return
2020-06-03 05:09:13 +02:00
}
2023-02-01 00:49:07 +01:00
sdkAnnotations := findModuleOrErr ( ctx , files . annotationsModule )
if sdkAnnotations == nil {
if ! ctx . Config ( ) . AllowMissingDependencies ( ) {
2024-05-02 13:44:20 +02:00
ctx . Errorf ( "lint: missing module %s" , files . annotationsModule )
2023-02-01 00:49:07 +01:00
}
return
2021-06-08 20:11:21 +02:00
}
2023-02-01 00:49:07 +01:00
ctx . Build ( pctx , android . BuildParams {
Rule : android . CpIfChanged ,
Input : android . OutputFileForModule ( ctx , sdkAnnotations , "" ) ,
Output : copiedLintDatabaseFilesPath ( ctx , files . annotationCopiedName ) ,
} )
2020-06-03 05:09:13 +02:00
2023-02-01 00:49:07 +01:00
ctx . Build ( pctx , android . BuildParams {
Rule : android . CpIfChanged ,
Input : android . OutputFileForModule ( ctx , apiVersionsDb , ".api_versions.xml" ) ,
Output : copiedLintDatabaseFilesPath ( ctx , files . apiVersionsCopiedName ) ,
} )
}
2020-06-03 05:09:13 +02:00
}
2023-02-01 00:49:07 +01:00
func copiedLintDatabaseFilesPath ( ctx android . PathContext , name string ) android . WritablePath {
2021-06-08 20:11:21 +02:00
return android . PathForOutput ( ctx , "lint" , name )
2020-06-03 05:09:13 +02:00
}
func ( l * lintSingleton ) generateLintReportZips ( ctx android . SingletonContext ) {
2020-07-06 20:45:51 +02:00
if ctx . Config ( ) . UnbundledBuild ( ) {
return
}
2020-06-03 05:09:13 +02:00
var outputs [ ] * lintOutputs
var dirs [ ] string
ctx . VisitAllModules ( func ( m android . Module ) {
2020-11-23 06:22:30 +01:00
if ctx . Config ( ) . KatiEnabled ( ) && ! m . ExportedToMake ( ) {
2020-06-03 05:09:13 +02:00
return
}
2020-09-16 03:30:11 +02:00
if apex , ok := m . ( android . ApexModule ) ; ok && apex . NotAvailableForPlatform ( ) {
2023-12-14 23:46:23 +01:00
apexInfo , _ := android . SingletonModuleProvider ( ctx , m , android . ApexInfoProvider )
2020-09-16 03:30:11 +02:00
if apexInfo . IsForPlatform ( ) {
// There are stray platform variants of modules in apexes that are not available for
// the platform, and they sometimes can't be built. Don't depend on them.
return
}
2020-06-03 05:09:13 +02:00
}
2020-07-22 05:31:17 +02:00
if l , ok := m . ( lintOutputsIntf ) ; ok {
2020-06-03 05:09:13 +02:00
outputs = append ( outputs , l . lintOutputs ( ) )
}
} )
dirs = android . SortedUniqueStrings ( dirs )
zip := func ( outputPath android . WritablePath , get func ( * lintOutputs ) android . Path ) {
var paths android . Paths
for _ , output := range outputs {
2020-07-22 05:31:17 +02:00
if p := get ( output ) ; p != nil {
paths = append ( paths , p )
}
2020-06-03 05:09:13 +02:00
}
2020-07-03 20:56:24 +02:00
lintZip ( ctx , paths , outputPath )
2020-06-03 05:09:13 +02:00
}
l . htmlZip = android . PathForOutput ( ctx , "lint-report-html.zip" )
zip ( l . htmlZip , func ( l * lintOutputs ) android . Path { return l . html } )
l . textZip = android . PathForOutput ( ctx , "lint-report-text.zip" )
zip ( l . textZip , func ( l * lintOutputs ) android . Path { return l . text } )
l . xmlZip = android . PathForOutput ( ctx , "lint-report-xml.zip" )
zip ( l . xmlZip , func ( l * lintOutputs ) android . Path { return l . xml } )
2023-03-03 01:43:15 +01:00
l . referenceBaselineZip = android . PathForOutput ( ctx , "lint-report-reference-baselines.zip" )
zip ( l . referenceBaselineZip , func ( l * lintOutputs ) android . Path { return l . referenceBaseline } )
ctx . Phony ( "lint-check" , l . htmlZip , l . textZip , l . xmlZip , l . referenceBaselineZip )
2020-06-03 05:09:13 +02:00
}
func ( l * lintSingleton ) MakeVars ( ctx android . MakeVarsContext ) {
2020-07-06 20:45:51 +02:00
if ! ctx . Config ( ) . UnbundledBuild ( ) {
2023-03-03 01:43:15 +01:00
ctx . DistForGoal ( "lint-check" , l . htmlZip , l . textZip , l . xmlZip , l . referenceBaselineZip )
2020-07-06 20:45:51 +02:00
}
2020-06-03 05:09:13 +02:00
}
var _ android . SingletonMakeVarsProvider = ( * lintSingleton ) ( nil )
func init ( ) {
2023-05-16 02:58:37 +02:00
android . RegisterParallelSingletonType ( "lint" ,
2020-06-03 05:09:13 +02:00
func ( ) android . Singleton { return & lintSingleton { } } )
2021-05-11 00:30:00 +02:00
registerLintBuildComponents ( android . InitRegistrationContext )
}
func registerLintBuildComponents ( ctx android . RegistrationContext ) {
ctx . PostDepsMutators ( func ( ctx android . RegisterMutatorsContext ) {
ctx . TopDown ( "enforce_strict_updatability_linting" , enforceStrictUpdatabilityLintingMutator ) . Parallel ( )
} )
2020-06-03 05:09:13 +02:00
}
2020-07-03 20:56:24 +02:00
func lintZip ( ctx android . BuilderContext , paths android . Paths , outputPath android . WritablePath ) {
paths = android . SortedUniquePaths ( android . CopyOfPaths ( paths ) )
sort . Slice ( paths , func ( i , j int ) bool {
return paths [ i ] . String ( ) < paths [ j ] . String ( )
} )
2020-11-17 02:32:30 +01:00
rule := android . NewRuleBuilder ( pctx , ctx )
2020-07-03 20:56:24 +02:00
2020-11-17 02:32:30 +01:00
rule . Command ( ) . BuiltTool ( "soong_zip" ) .
2020-07-03 20:56:24 +02:00
FlagWithOutput ( "-o " , outputPath ) .
FlagWithArg ( "-C " , android . PathForIntermediates ( ctx ) . String ( ) ) .
2021-03-13 02:48:14 +01:00
FlagWithRspFileInputList ( "-r " , outputPath . ReplaceExtension ( ctx , "rsp" ) , paths )
2020-07-03 20:56:24 +02:00
2020-11-17 02:32:30 +01:00
rule . Build ( outputPath . Base ( ) , outputPath . Base ( ) )
2020-07-03 20:56:24 +02:00
}
2021-05-11 00:30:00 +02:00
// Enforce the strict updatability linting to all applicable transitive dependencies.
func enforceStrictUpdatabilityLintingMutator ( ctx android . TopDownMutatorContext ) {
m := ctx . Module ( )
2022-01-14 22:19:14 +01:00
if d , ok := m . ( LintDepSetsIntf ) ; ok && d . GetStrictUpdatabilityLinting ( ) {
2021-05-11 00:30:00 +02:00
ctx . VisitDirectDepsWithTag ( staticLibTag , func ( d android . Module ) {
2022-01-14 22:19:14 +01:00
if a , ok := d . ( LintDepSetsIntf ) ; ok {
a . SetStrictUpdatabilityLinting ( true )
2021-05-11 00:30:00 +02:00
}
} )
}
}