blob: ac90e19ba8759eccc93928d6cb06ee897206caa5 [file] [log] [blame]
Colin Cross014489c2020-06-02 20:09:13 -07001// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18 "fmt"
19 "sort"
Colin Cross988dfcc2020-07-16 17:32:17 -070020 "strings"
Colin Cross014489c2020-06-02 20:09:13 -070021
Colin Crossb79aa8f2024-09-25 15:41:01 -070022 "github.com/google/blueprint"
Colin Crossa14fb6a2024-10-23 16:57:06 -070023 "github.com/google/blueprint/depset"
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000024 "github.com/google/blueprint/proptools"
25
Colin Cross014489c2020-06-02 20:09:13 -070026 "android/soong/android"
Colin Cross31972dc2021-03-04 10:44:12 -080027 "android/soong/java/config"
28 "android/soong/remoteexec"
Colin Cross014489c2020-06-02 20:09:13 -070029)
30
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -070031// lint checks automatically enforced for modules that have different min_sdk_version than
32// sdk_version
33var updatabilityChecks = []string{"NewApi"}
34
Colin Cross014489c2020-06-02 20:09:13 -070035type LintProperties struct {
36 // Controls for running Android Lint on the module.
37 Lint struct {
38
39 // If true, run Android Lint on the module. Defaults to true.
40 Enabled *bool
41
42 // Flags to pass to the Android Lint tool.
43 Flags []string
44
45 // Checks that should be treated as fatal.
46 Fatal_checks []string
47
48 // Checks that should be treated as errors.
49 Error_checks []string
50
51 // Checks that should be treated as warnings.
52 Warning_checks []string
53
54 // Checks that should be skipped.
55 Disabled_checks []string
Colin Cross92e4b462020-06-18 15:56:48 -070056
57 // Modules that provide extra lint checks
58 Extra_check_modules []string
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000059
Cole Faustb765d6b2024-01-04 10:29:27 -080060 // The lint baseline file to use. If specified, lint warnings listed in this file will be
61 // suppressed during lint checks.
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000062 Baseline_filename *string
Jaewoong Jung48de8832021-04-21 16:17:25 -070063
64 // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
65 Strict_updatability_linting *bool
Cole Faustd57e8b22022-08-11 11:59:04 -070066
67 // Treat the code in this module as test code for @VisibleForTesting enforcement.
68 // This will be true by default for test module types, false otherwise.
69 // If soong gets support for testonly, this flag should be replaced with that.
70 Test *bool
ThiƩbaud Weksteen9c0dff92023-09-29 10:21:56 +100071
72 // Whether to ignore the exit code of Android lint. This is the --exit_code
73 // option. Defaults to false.
74 Suppress_exit_code *bool
Colin Cross014489c2020-06-02 20:09:13 -070075 }
76}
77
78type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000079 name string
80 manifest android.Path
81 mergedManifest android.Path
82 srcs android.Paths
83 srcJars android.Paths
84 resources android.Paths
85 classpath android.Paths
86 classes android.Path
87 extraLintCheckJars android.Paths
Pedro Loureirof4a88b12021-02-25 16:23:22 +000088 library bool
Zi Wange1166f02023-11-06 11:43:17 -080089 minSdkVersion android.ApiLevel
90 targetSdkVersion android.ApiLevel
91 compileSdkVersion android.ApiLevel
Pedro Loureiro18233a22021-06-08 18:11:21 +000092 compileSdkKind android.SdkKind
Pedro Loureirof4a88b12021-02-25 16:23:22 +000093 javaLanguageLevel string
94 kotlinLanguageLevel string
Pedro Loureirof4a88b12021-02-25 16:23:22 +000095 properties LintProperties
96 extraMainlineLintErrors []string
Cole Faustdf1efd72023-12-08 12:27:24 -080097 compile_data android.Paths
Colin Crossc0efd1d2020-07-03 11:56:24 -070098
Colin Cross08dca382020-07-21 20:31:17 -070099 reports android.Paths
100
Colin Crossc0efd1d2020-07-03 11:56:24 -0700101 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -0700102}
103
Colin Cross08dca382020-07-21 20:31:17 -0700104type LintDepSets struct {
Colin Crossa14fb6a2024-10-23 16:57:06 -0700105 HTML, Text, XML, Baseline depset.DepSet[android.Path]
Colin Cross08dca382020-07-21 20:31:17 -0700106}
107
108type LintDepSetsBuilder struct {
Colin Crossa14fb6a2024-10-23 16:57:06 -0700109 HTML, Text, XML, Baseline *depset.Builder[android.Path]
Colin Cross08dca382020-07-21 20:31:17 -0700110}
111
112func NewLintDepSetBuilder() LintDepSetsBuilder {
113 return LintDepSetsBuilder{
Colin Crossa14fb6a2024-10-23 16:57:06 -0700114 HTML: depset.NewBuilder[android.Path](depset.POSTORDER),
115 Text: depset.NewBuilder[android.Path](depset.POSTORDER),
116 XML: depset.NewBuilder[android.Path](depset.POSTORDER),
117 Baseline: depset.NewBuilder[android.Path](depset.POSTORDER),
Colin Cross08dca382020-07-21 20:31:17 -0700118 }
119}
120
Colin Cross87427352024-09-25 15:41:19 -0700121func (l LintDepSetsBuilder) Direct(html, text, xml android.Path, baseline android.OptionalPath) LintDepSetsBuilder {
Colin Cross08dca382020-07-21 20:31:17 -0700122 l.HTML.Direct(html)
123 l.Text.Direct(text)
124 l.XML.Direct(xml)
Colin Cross87427352024-09-25 15:41:19 -0700125 if baseline.Valid() {
126 l.Baseline.Direct(baseline.Path())
127 }
Colin Cross08dca382020-07-21 20:31:17 -0700128 return l
129}
130
Colin Crossb79aa8f2024-09-25 15:41:01 -0700131func (l LintDepSetsBuilder) Transitive(info *LintInfo) LintDepSetsBuilder {
Colin Crossa14fb6a2024-10-23 16:57:06 -0700132 l.HTML.Transitive(info.TransitiveHTML)
133 l.Text.Transitive(info.TransitiveText)
134 l.XML.Transitive(info.TransitiveXML)
135 l.Baseline.Transitive(info.TransitiveBaseline)
Colin Cross08dca382020-07-21 20:31:17 -0700136 return l
137}
138
139func (l LintDepSetsBuilder) Build() LintDepSets {
140 return LintDepSets{
Colin Cross87427352024-09-25 15:41:19 -0700141 HTML: l.HTML.Build(),
142 Text: l.Text.Build(),
143 XML: l.XML.Build(),
144 Baseline: l.Baseline.Build(),
Colin Cross08dca382020-07-21 20:31:17 -0700145 }
146}
147
Cole Faust69861aa2023-01-31 15:49:07 -0800148type lintDatabaseFiles struct {
149 apiVersionsModule string
150 apiVersionsCopiedName string
151 apiVersionsPrebuiltPath string
152 annotationsModule string
153 annotationCopiedName string
154 annotationPrebuiltpath string
155}
156
157var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{
158 android.SdkPublic: {
159 apiVersionsModule: "api_versions_public",
160 apiVersionsCopiedName: "api_versions_public.xml",
161 apiVersionsPrebuiltPath: "prebuilts/sdk/current/public/data/api-versions.xml",
162 annotationsModule: "sdk-annotations.zip",
163 annotationCopiedName: "annotations-public.zip",
164 annotationPrebuiltpath: "prebuilts/sdk/current/public/data/annotations.zip",
165 },
166 android.SdkSystem: {
167 apiVersionsModule: "api_versions_system",
168 apiVersionsCopiedName: "api_versions_system.xml",
169 apiVersionsPrebuiltPath: "prebuilts/sdk/current/system/data/api-versions.xml",
170 annotationsModule: "sdk-annotations-system.zip",
171 annotationCopiedName: "annotations-system.zip",
172 annotationPrebuiltpath: "prebuilts/sdk/current/system/data/annotations.zip",
173 },
174 android.SdkModule: {
175 apiVersionsModule: "api_versions_module_lib",
176 apiVersionsCopiedName: "api_versions_module_lib.xml",
177 apiVersionsPrebuiltPath: "prebuilts/sdk/current/module-lib/data/api-versions.xml",
178 annotationsModule: "sdk-annotations-module-lib.zip",
179 annotationCopiedName: "annotations-module-lib.zip",
180 annotationPrebuiltpath: "prebuilts/sdk/current/module-lib/data/annotations.zip",
181 },
182 android.SdkSystemServer: {
183 apiVersionsModule: "api_versions_system_server",
184 apiVersionsCopiedName: "api_versions_system_server.xml",
185 apiVersionsPrebuiltPath: "prebuilts/sdk/current/system-server/data/api-versions.xml",
186 annotationsModule: "sdk-annotations-system-server.zip",
187 annotationCopiedName: "annotations-system-server.zip",
188 annotationPrebuiltpath: "prebuilts/sdk/current/system-server/data/annotations.zip",
189 },
190}
191
Colin Crossb79aa8f2024-09-25 15:41:01 -0700192var LintProvider = blueprint.NewProvider[*LintInfo]()
Colin Crossc0efd1d2020-07-03 11:56:24 -0700193
Colin Crossb79aa8f2024-09-25 15:41:01 -0700194type LintInfo struct {
195 HTML android.Path
196 Text android.Path
197 XML android.Path
198 ReferenceBaseline android.Path
199
Colin Crossa14fb6a2024-10-23 16:57:06 -0700200 TransitiveHTML depset.DepSet[android.Path]
201 TransitiveText depset.DepSet[android.Path]
202 TransitiveXML depset.DepSet[android.Path]
203 TransitiveBaseline depset.DepSet[android.Path]
Colin Cross014489c2020-06-02 20:09:13 -0700204}
205
206func (l *linter) enabled() bool {
207 return BoolDefault(l.properties.Lint.Enabled, true)
208}
209
Colin Cross92e4b462020-06-18 15:56:48 -0700210func (l *linter) deps(ctx android.BottomUpMutatorContext) {
211 if !l.enabled() {
212 return
213 }
214
Colin Cross988dfcc2020-07-16 17:32:17 -0700215 extraCheckModules := l.properties.Lint.Extra_check_modules
216
mattgilbridee17645f2022-11-18 18:20:20 +0000217 if extraCheckModulesEnv := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); extraCheckModulesEnv != "" {
218 extraCheckModules = append(extraCheckModules, strings.Split(extraCheckModulesEnv, ",")...)
Colin Cross988dfcc2020-07-16 17:32:17 -0700219 }
220
221 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
222 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700223}
224
Colin Crossad22bc22021-03-10 09:45:40 -0800225// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
226// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800227type lintPaths struct {
228 projectXML android.WritablePath
229 configXML android.WritablePath
230 cacheDir android.WritablePath
231 homeDir android.WritablePath
232 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800233}
234
Colin Cross9b93af42021-03-10 10:40:58 -0800235func lintRBEExecStrategy(ctx android.ModuleContext) string {
236 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
237}
238
Colin Cross87427352024-09-25 15:41:19 -0700239func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path,
240 baselines android.Paths) lintPaths {
241
Colin Cross31972dc2021-03-04 10:44:12 -0800242 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700243 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800244 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
245 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
246 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700247
Colin Cross1661aff2021-03-12 17:56:51 -0800248 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700249 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
250
251 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700252 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700253 FlagWithOutput("--project_out ", projectXMLPath).
254 FlagWithOutput("--config_out ", configXMLPath).
255 FlagWithArg("--name ", ctx.ModuleName())
256
257 if l.library {
258 cmd.Flag("--library")
259 }
Cole Faustd57e8b22022-08-11 11:59:04 -0700260 if proptools.BoolDefault(l.properties.Lint.Test, false) {
Colin Cross014489c2020-06-02 20:09:13 -0700261 cmd.Flag("--test")
262 }
263 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700264 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700265 }
266 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700267 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700268 }
269
Colin Cross5bedfa22021-03-23 17:07:14 -0700270 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
271 // lint separately.
Colin Cross62695b92022-08-12 16:09:24 -0700272 cmd.FlagWithInput("--srcs ", srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700273
274 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700275
Colin Cross5bedfa22021-03-23 17:07:14 -0700276 if len(l.resources) > 0 {
277 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
278 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700279 }
280
281 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700282 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700283 }
284
Colin Cross5bedfa22021-03-23 17:07:14 -0700285 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700286
Colin Cross5bedfa22021-03-23 17:07:14 -0700287 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700288
Colin Cross1661aff2021-03-12 17:56:51 -0800289 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700290
291 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
292 // the root dir is not set.
293 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700294
295 cmd.FlagWithInput("@",
296 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
297
Cole Faust028b94c2024-01-16 17:17:11 -0800298 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700299 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
300 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
301 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
302 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
303
Colin Cross87427352024-09-25 15:41:19 -0700304 if Bool(l.properties.Lint.Strict_updatability_linting) && len(baselines) > 0 {
Cole Faust24e25c02024-01-19 14:12:17 -0800305 // Verify the module does not baseline issues that endanger safe updatability.
Colin Cross87427352024-09-25 15:41:19 -0700306 strictUpdatabilityChecksOutputFile := VerifyStrictUpdatabilityChecks(ctx, baselines)
307 cmd.Validation(strictUpdatabilityChecksOutputFile)
Cole Faust24e25c02024-01-19 14:12:17 -0800308 }
Jaewoong Jung48de8832021-04-21 16:17:25 -0700309
Colin Cross31972dc2021-03-04 10:44:12 -0800310 return lintPaths{
311 projectXML: projectXMLPath,
312 configXML: configXMLPath,
313 cacheDir: cacheDir,
314 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800315 }
316
Colin Cross014489c2020-06-02 20:09:13 -0700317}
318
Colin Cross87427352024-09-25 15:41:19 -0700319func VerifyStrictUpdatabilityChecks(ctx android.ModuleContext, baselines android.Paths) android.Path {
320 rule := android.NewRuleBuilder(pctx, ctx)
321 baselineRspFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check_baselines.rsp")
322 outputFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check.stamp")
323 rule.Command().Text("rm -f").Output(outputFile)
324 rule.Command().
325 BuiltTool("lint_strict_updatability_checks").
326 FlagWithArg("--name ", ctx.ModuleName()).
327 FlagWithRspFileInputList("--baselines ", baselineRspFile, baselines).
328 FlagForEachArg("--disallowed_issues ", updatabilityChecks)
329 rule.Command().Text("touch").Output(outputFile)
330 rule.Build("lint_strict_updatability_checks", "lint strict updatability checks")
331
332 return outputFile
333}
334
Liz Kammer20ebfb42020-07-28 11:32:07 -0700335// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700336// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800337func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700338 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
339
340 rule.Command().Text("(").
341 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
342 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
343 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Zi Wange1166f02023-11-06 11:43:17 -0800344 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
345 l.minSdkVersion.String(), l.targetSdkVersion.String()).
Colin Cross014489c2020-06-02 20:09:13 -0700346 Text(`echo "</manifest>"`).
347 Text(") >").Output(manifestPath)
348
349 return manifestPath
350}
351
352func (l *linter) lint(ctx android.ModuleContext) {
353 if !l.enabled() {
354 return
355 }
356
Cole Faust5d0aaf42024-01-29 13:49:14 -0800357 for _, flag := range l.properties.Lint.Flags {
358 if strings.Contains(flag, "--disable") || strings.Contains(flag, "--enable") || strings.Contains(flag, "--check") {
359 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")
360 }
361 }
362
Zi Wange1166f02023-11-06 11:43:17 -0800363 if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700364 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
Orion Hodsonb8166522022-08-15 20:23:38 +0100365 // Skip lint warning checks for NewApi warnings for libcore where they come from source
366 // files that reference the API they are adding (b/208656169).
Orion Hodsonb2d3c8c2022-10-25 16:45:14 +0100367 if !strings.HasPrefix(ctx.ModuleDir(), "libcore") {
Orion Hodsonb8166522022-08-15 20:23:38 +0100368 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
369
370 if len(filtered) != 0 {
371 ctx.PropertyErrorf("lint.warning_checks",
372 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
373 }
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700374 }
Orion Hodsonb8166522022-08-15 20:23:38 +0100375
376 _, filtered := android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700377 if len(filtered) != 0 {
378 ctx.PropertyErrorf("lint.disabled_checks",
379 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
380 }
Cole Faust3f646262022-06-29 14:58:03 -0700381
382 // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
383 if ctx.ModuleName() == "PermissionController" {
384 l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
385 return s != "NewApi"
386 })
387 l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
388 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000389 }
390
Colin Cross92e4b462020-06-18 15:56:48 -0700391 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
392 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Cross313aa542023-12-13 13:47:44 -0800393 if dep, ok := android.OtherModuleProvider(ctx, extraLintCheckModule, JavaInfoProvider); ok {
Colin Crossdcf71b22021-02-01 13:59:03 -0800394 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700395 } else {
396 ctx.PropertyErrorf("lint.extra_check_modules",
397 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
398 }
399 }
400
mattgilbride5aecabe2022-11-29 20:16:36 +0000401 l.extraLintCheckJars = append(l.extraLintCheckJars, android.PathForSource(ctx,
402 "prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar"))
403
Colin Cross87427352024-09-25 15:41:19 -0700404 var baseline android.OptionalPath
405 if l.properties.Lint.Baseline_filename != nil {
406 baseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
407 }
408
409 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
410 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
411 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
412 referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
413
414 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml, baseline)
415
416 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
417 if info, ok := android.OtherModuleProvider(ctx, dep, LintProvider); ok {
418 depSetsBuilder.Transitive(info)
419 }
420 })
421
422 depSets := depSetsBuilder.Build()
423
Colin Cross1661aff2021-03-12 17:56:51 -0800424 rule := android.NewRuleBuilder(pctx, ctx).
425 Sbox(android.PathForModuleOut(ctx, "lint"),
426 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
427 SandboxInputs()
428
429 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
430 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
431 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
432 rule.Rewrapper(&remoteexec.REParams{
433 Labels: map[string]string{"type": "tool", "name": "lint"},
434 ExecStrategy: lintRBEExecStrategy(ctx),
435 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700436 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800437 })
438 }
Colin Cross014489c2020-06-02 20:09:13 -0700439
440 if l.manifest == nil {
441 manifest := l.generateManifest(ctx, rule)
442 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800443 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700444 }
445
Colin Cross62695b92022-08-12 16:09:24 -0700446 srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
447 srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
Cole Faustdf1efd72023-12-08 12:27:24 -0800448 rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList).Implicits(l.compile_data)
Colin Cross62695b92022-08-12 16:09:24 -0700449
Colin Cross87427352024-09-25 15:41:19 -0700450 baselines := depSets.Baseline.ToList()
Colin Cross014489c2020-06-02 20:09:13 -0700451
Colin Cross87427352024-09-25 15:41:19 -0700452 lintPaths := l.writeLintProjectXML(ctx, rule, srcsList, baselines)
Colin Crossb79aa8f2024-09-25 15:41:01 -0700453
Colin Cross31972dc2021-03-04 10:44:12 -0800454 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
455 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800456 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700457
Cole Faust69861aa2023-01-31 15:49:07 -0800458 files, ok := allLintDatabasefiles[l.compileSdkKind]
459 if !ok {
460 files = allLintDatabasefiles[android.SdkPublic]
Pedro Loureiro18233a22021-06-08 18:11:21 +0000461 }
Colin Cross8a6ed372020-07-06 11:45:51 -0700462 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900463 if ctx.Config().AlwaysUsePrebuiltSdks() {
Cole Faust69861aa2023-01-31 15:49:07 -0800464 annotationsZipPath = android.PathForSource(ctx, files.annotationPrebuiltpath)
465 apiVersionsXMLPath = android.PathForSource(ctx, files.apiVersionsPrebuiltPath)
Colin Cross8a6ed372020-07-06 11:45:51 -0700466 } else {
Cole Faust69861aa2023-01-31 15:49:07 -0800467 annotationsZipPath = copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName)
468 apiVersionsXMLPath = copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700469 }
470
Colin Cross31972dc2021-03-04 10:44:12 -0800471 cmd := rule.Command()
472
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000473 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800474 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700475 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800476 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
477
Colin Cross1661aff2021-03-12 17:56:51 -0800478 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700479 Flag("--quiet").
Tor Norbyecabafde2023-12-07 21:57:28 +0000480 Flag("--include-aosp-issues").
Colin Cross31972dc2021-03-04 10:44:12 -0800481 FlagWithInput("--project ", lintPaths.projectXML).
482 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700483 FlagWithOutput("--html ", html).
484 FlagWithOutput("--text ", text).
485 FlagWithOutput("--xml ", xml).
Zi Wange1166f02023-11-06 11:43:17 -0800486 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
Colin Cross014489c2020-06-02 20:09:13 -0700487 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
488 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
489 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
Colin Cross62695b92022-08-12 16:09:24 -0700490 Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
Colin Cross014489c2020-06-02 20:09:13 -0700491 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800492 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700493 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700494
Colin Cross1661aff2021-03-12 17:56:51 -0800495 rule.Temporary(lintPaths.projectXML)
496 rule.Temporary(lintPaths.configXML)
497
ThiƩbaud Weksteen9c0dff92023-09-29 10:21:56 +1000498 suppressExitCode := BoolDefault(l.properties.Lint.Suppress_exit_code, false)
499 if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" && !suppressExitCode {
mattgilbrideb597abd2023-03-22 17:44:18 +0000500 cmd.Flag("--exitcode")
501 }
502
Colin Cross988dfcc2020-07-16 17:32:17 -0700503 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
504 cmd.FlagWithArg("--check ", checkOnly)
505 }
506
Colin Cross87427352024-09-25 15:41:19 -0700507 if baseline.Valid() {
508 cmd.FlagWithInput("--baseline ", baseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000509 }
510
Cole Faustdf38f7a2023-03-02 16:43:15 -0800511 cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
Colin Cross6b76c152021-09-09 09:36:25 -0700512
Colin Cross1b9e6832022-10-11 11:22:24 -0700513 cmd.Text("; EXITCODE=$?; ")
514
515 // The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
516 // export them out of the sandbox. Do this before exiting so that the suggestions exit even after
517 // a fatal error.
518 cmd.BuiltTool("soong_zip").
519 FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
520 FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
521 FlagWithInput("-r ", srcsList)
522
523 cmd.Text("; if [ $EXITCODE != 0 ]; then if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit $EXITCODE; fi")
Colin Cross014489c2020-06-02 20:09:13 -0700524
Colin Cross31972dc2021-03-04 10:44:12 -0800525 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700526
Colin Crossee4a8b72021-04-05 18:38:05 -0700527 // The HTML output contains a date, remove it to make the output deterministic.
528 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
529
Colin Crossf1a035e2020-11-16 17:32:30 -0800530 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700531
Colin Crossb79aa8f2024-09-25 15:41:01 -0700532 android.SetProvider(ctx, LintProvider, &LintInfo{
533 HTML: html,
534 Text: text,
535 XML: xml,
536 ReferenceBaseline: referenceBaseline,
Colin Cross014489c2020-06-02 20:09:13 -0700537
Colin Cross87427352024-09-25 15:41:19 -0700538 TransitiveHTML: depSets.HTML,
539 TransitiveText: depSets.Text,
540 TransitiveXML: depSets.XML,
541 TransitiveBaseline: depSets.Baseline,
Colin Crossb79aa8f2024-09-25 15:41:01 -0700542 })
Colin Cross014489c2020-06-02 20:09:13 -0700543
Colin Crossc0efd1d2020-07-03 11:56:24 -0700544 if l.buildModuleReportZip {
Colin Cross87427352024-09-25 15:41:19 -0700545 l.reports = BuildModuleLintReportZips(ctx, depSets, nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700546 }
Colin Crossb9176412024-01-05 12:51:25 -0800547
548 // Create a per-module phony target to run the lint check.
549 phonyName := ctx.ModuleName() + "-lint"
550 ctx.Phony(phonyName, xml)
Colin Crossb79aa8f2024-09-25 15:41:01 -0700551
552 ctx.SetOutputFiles(android.Paths{xml}, ".lint")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700553}
Colin Cross014489c2020-06-02 20:09:13 -0700554
Colin Cross87427352024-09-25 15:41:19 -0700555func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets, validations android.Paths) android.Paths {
Colin Crossc85750b2022-04-21 12:50:51 -0700556 htmlList := android.SortedUniquePaths(depSets.HTML.ToList())
557 textList := android.SortedUniquePaths(depSets.Text.ToList())
558 xmlList := android.SortedUniquePaths(depSets.XML.ToList())
Colin Cross08dca382020-07-21 20:31:17 -0700559
560 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
561 return nil
562 }
563
564 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
Colin Cross87427352024-09-25 15:41:19 -0700565 lintZip(ctx, htmlList, htmlZip, validations)
Colin Cross08dca382020-07-21 20:31:17 -0700566
567 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
Colin Cross87427352024-09-25 15:41:19 -0700568 lintZip(ctx, textList, textZip, validations)
Colin Cross08dca382020-07-21 20:31:17 -0700569
570 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
Colin Cross87427352024-09-25 15:41:19 -0700571 lintZip(ctx, xmlList, xmlZip, validations)
Colin Cross08dca382020-07-21 20:31:17 -0700572
573 return android.Paths{htmlZip, textZip, xmlZip}
574}
575
Colin Cross014489c2020-06-02 20:09:13 -0700576type lintSingleton struct {
Cole Faustdf38f7a2023-03-02 16:43:15 -0800577 htmlZip android.WritablePath
578 textZip android.WritablePath
579 xmlZip android.WritablePath
580 referenceBaselineZip android.WritablePath
Colin Cross014489c2020-06-02 20:09:13 -0700581}
582
583func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
584 l.generateLintReportZips(ctx)
585 l.copyLintDependencies(ctx)
586}
587
Pedro Loureiro18233a22021-06-08 18:11:21 +0000588func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
589 var res android.Module
590 ctx.VisitAllModules(func(m android.Module) {
591 if ctx.ModuleName(m) == moduleName {
592 if res == nil {
593 res = m
594 } else {
595 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
596 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
597 }
598 }
599 })
600 return res
601}
602
Colin Cross014489c2020-06-02 20:09:13 -0700603func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900604 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700605 return
606 }
607
Cole Faust69861aa2023-01-31 15:49:07 -0800608 for _, sdk := range android.SortedKeys(allLintDatabasefiles) {
609 files := allLintDatabasefiles[sdk]
610 apiVersionsDb := findModuleOrErr(ctx, files.apiVersionsModule)
611 if apiVersionsDb == nil {
612 if !ctx.Config().AllowMissingDependencies() {
Paul Duffin375acd82024-05-02 12:44:20 +0100613 ctx.Errorf("lint: missing module %s", files.apiVersionsModule)
Cole Faust69861aa2023-01-31 15:49:07 -0800614 }
615 return
Colin Cross014489c2020-06-02 20:09:13 -0700616 }
Colin Cross014489c2020-06-02 20:09:13 -0700617
Cole Faust69861aa2023-01-31 15:49:07 -0800618 sdkAnnotations := findModuleOrErr(ctx, files.annotationsModule)
619 if sdkAnnotations == nil {
620 if !ctx.Config().AllowMissingDependencies() {
Paul Duffin375acd82024-05-02 12:44:20 +0100621 ctx.Errorf("lint: missing module %s", files.annotationsModule)
Cole Faust69861aa2023-01-31 15:49:07 -0800622 }
623 return
Anton Hanssonea17a452022-05-09 09:42:17 +0000624 }
Cole Faust69861aa2023-01-31 15:49:07 -0800625
626 ctx.Build(pctx, android.BuildParams{
627 Rule: android.CpIfChanged,
628 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
629 Output: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
630 })
631
632 ctx.Build(pctx, android.BuildParams{
633 Rule: android.CpIfChanged,
634 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
635 Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
636 })
Anton Hanssonea17a452022-05-09 09:42:17 +0000637 }
Colin Cross014489c2020-06-02 20:09:13 -0700638}
639
Cole Faust69861aa2023-01-31 15:49:07 -0800640func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.WritablePath {
Pedro Loureiro18233a22021-06-08 18:11:21 +0000641 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700642}
643
644func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700645 if ctx.Config().UnbundledBuild() {
646 return
647 }
648
Colin Crossb79aa8f2024-09-25 15:41:01 -0700649 var outputs []*LintInfo
Colin Cross014489c2020-06-02 20:09:13 -0700650 var dirs []string
651 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500652 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700653 return
654 }
655
Colin Cross56a83212020-09-15 18:30:11 -0700656 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
Yu Liu663e4502024-08-12 18:23:59 +0000657 apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
Colin Cross56a83212020-09-15 18:30:11 -0700658 if apexInfo.IsForPlatform() {
659 // There are stray platform variants of modules in apexes that are not available for
660 // the platform, and they sometimes can't be built. Don't depend on them.
661 return
662 }
Colin Cross014489c2020-06-02 20:09:13 -0700663 }
664
Colin Crossb79aa8f2024-09-25 15:41:01 -0700665 if lintInfo, ok := android.OtherModuleProvider(ctx, m, LintProvider); ok {
666 outputs = append(outputs, lintInfo)
Colin Cross014489c2020-06-02 20:09:13 -0700667 }
668 })
669
670 dirs = android.SortedUniqueStrings(dirs)
671
Colin Crossb79aa8f2024-09-25 15:41:01 -0700672 zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) {
Colin Cross014489c2020-06-02 20:09:13 -0700673 var paths android.Paths
674
675 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700676 if p := get(output); p != nil {
677 paths = append(paths, p)
678 }
Colin Cross014489c2020-06-02 20:09:13 -0700679 }
680
Colin Cross87427352024-09-25 15:41:19 -0700681 lintZip(ctx, paths, outputPath, nil)
Colin Cross014489c2020-06-02 20:09:13 -0700682 }
683
684 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700685 zip(l.htmlZip, func(l *LintInfo) android.Path { return l.HTML })
Colin Cross014489c2020-06-02 20:09:13 -0700686
687 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700688 zip(l.textZip, func(l *LintInfo) android.Path { return l.Text })
Colin Cross014489c2020-06-02 20:09:13 -0700689
690 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700691 zip(l.xmlZip, func(l *LintInfo) android.Path { return l.XML })
Colin Cross014489c2020-06-02 20:09:13 -0700692
Cole Faustdf38f7a2023-03-02 16:43:15 -0800693 l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700694 zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline })
Cole Faustdf38f7a2023-03-02 16:43:15 -0800695
696 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
Colin Cross014489c2020-06-02 20:09:13 -0700697}
698
699func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700700 if !ctx.Config().UnbundledBuild() {
Cole Faustdf38f7a2023-03-02 16:43:15 -0800701 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
Colin Cross8a6ed372020-07-06 11:45:51 -0700702 }
Colin Cross014489c2020-06-02 20:09:13 -0700703}
704
705var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
706
707func init() {
LaMont Jones0c10e4d2023-05-16 00:58:37 +0000708 android.RegisterParallelSingletonType("lint",
Colin Cross014489c2020-06-02 20:09:13 -0700709 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700710}
711
Colin Cross87427352024-09-25 15:41:19 -0700712func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath, validations android.Paths) {
Colin Crossc0efd1d2020-07-03 11:56:24 -0700713 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
714
715 sort.Slice(paths, func(i, j int) bool {
716 return paths[i].String() < paths[j].String()
717 })
718
Colin Crossf1a035e2020-11-16 17:32:30 -0800719 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700720
Colin Crossf1a035e2020-11-16 17:32:30 -0800721 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700722 FlagWithOutput("-o ", outputPath).
723 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross87427352024-09-25 15:41:19 -0700724 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths).
725 Validations(validations)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700726
Colin Crossf1a035e2020-11-16 17:32:30 -0800727 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700728}