blob: 5cd49a8b7a1bf9b9fb5432657da3afa9bc3bf6da [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"
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000023 "github.com/google/blueprint/proptools"
24
Colin Cross014489c2020-06-02 20:09:13 -070025 "android/soong/android"
Colin Cross31972dc2021-03-04 10:44:12 -080026 "android/soong/java/config"
27 "android/soong/remoteexec"
Colin Cross014489c2020-06-02 20:09:13 -070028)
29
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -070030// lint checks automatically enforced for modules that have different min_sdk_version than
31// sdk_version
32var updatabilityChecks = []string{"NewApi"}
33
Colin Cross014489c2020-06-02 20:09:13 -070034type LintProperties struct {
35 // Controls for running Android Lint on the module.
36 Lint struct {
37
38 // If true, run Android Lint on the module. Defaults to true.
39 Enabled *bool
40
41 // Flags to pass to the Android Lint tool.
42 Flags []string
43
44 // Checks that should be treated as fatal.
45 Fatal_checks []string
46
47 // Checks that should be treated as errors.
48 Error_checks []string
49
50 // Checks that should be treated as warnings.
51 Warning_checks []string
52
53 // Checks that should be skipped.
54 Disabled_checks []string
Colin Cross92e4b462020-06-18 15:56:48 -070055
56 // Modules that provide extra lint checks
57 Extra_check_modules []string
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000058
Cole Faustb765d6b2024-01-04 10:29:27 -080059 // The lint baseline file to use. If specified, lint warnings listed in this file will be
60 // suppressed during lint checks.
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000061 Baseline_filename *string
Jaewoong Jung48de8832021-04-21 16:17:25 -070062
63 // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
64 Strict_updatability_linting *bool
Cole Faustd57e8b22022-08-11 11:59:04 -070065
66 // Treat the code in this module as test code for @VisibleForTesting enforcement.
67 // This will be true by default for test module types, false otherwise.
68 // If soong gets support for testonly, this flag should be replaced with that.
69 Test *bool
ThiƩbaud Weksteen9c0dff92023-09-29 10:21:56 +100070
71 // Whether to ignore the exit code of Android lint. This is the --exit_code
72 // option. Defaults to false.
73 Suppress_exit_code *bool
Colin Cross014489c2020-06-02 20:09:13 -070074 }
75}
76
77type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000078 name string
79 manifest android.Path
80 mergedManifest android.Path
81 srcs android.Paths
82 srcJars android.Paths
83 resources android.Paths
84 classpath android.Paths
85 classes android.Path
86 extraLintCheckJars android.Paths
Pedro Loureirof4a88b12021-02-25 16:23:22 +000087 library bool
Zi Wange1166f02023-11-06 11:43:17 -080088 minSdkVersion android.ApiLevel
89 targetSdkVersion android.ApiLevel
90 compileSdkVersion android.ApiLevel
Pedro Loureiro18233a22021-06-08 18:11:21 +000091 compileSdkKind android.SdkKind
Pedro Loureirof4a88b12021-02-25 16:23:22 +000092 javaLanguageLevel string
93 kotlinLanguageLevel string
Pedro Loureirof4a88b12021-02-25 16:23:22 +000094 properties LintProperties
95 extraMainlineLintErrors []string
Cole Faustdf1efd72023-12-08 12:27:24 -080096 compile_data android.Paths
Colin Crossc0efd1d2020-07-03 11:56:24 -070097
Colin Cross08dca382020-07-21 20:31:17 -070098 reports android.Paths
99
Colin Crossc0efd1d2020-07-03 11:56:24 -0700100 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -0700101}
102
Spandan Das17854f52022-01-14 21:19:14 +0000103type LintDepSetsIntf interface {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700104 // Methods used to propagate strict_updatability_linting values.
Spandan Das17854f52022-01-14 21:19:14 +0000105 GetStrictUpdatabilityLinting() bool
106 SetStrictUpdatabilityLinting(bool)
Colin Cross08dca382020-07-21 20:31:17 -0700107}
108
109type LintDepSets struct {
Colin Crossc85750b2022-04-21 12:50:51 -0700110 HTML, Text, XML *android.DepSet[android.Path]
Colin Cross08dca382020-07-21 20:31:17 -0700111}
112
113type LintDepSetsBuilder struct {
Colin Crossc85750b2022-04-21 12:50:51 -0700114 HTML, Text, XML *android.DepSetBuilder[android.Path]
Colin Cross08dca382020-07-21 20:31:17 -0700115}
116
117func NewLintDepSetBuilder() LintDepSetsBuilder {
118 return LintDepSetsBuilder{
Colin Crossc85750b2022-04-21 12:50:51 -0700119 HTML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
120 Text: android.NewDepSetBuilder[android.Path](android.POSTORDER),
121 XML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
Colin Cross08dca382020-07-21 20:31:17 -0700122 }
123}
124
125func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
126 l.HTML.Direct(html)
127 l.Text.Direct(text)
128 l.XML.Direct(xml)
129 return l
130}
131
Colin Crossb79aa8f2024-09-25 15:41:01 -0700132func (l LintDepSetsBuilder) Transitive(info *LintInfo) LintDepSetsBuilder {
133 if info.TransitiveHTML != nil {
134 l.HTML.Transitive(info.TransitiveHTML)
Colin Cross08dca382020-07-21 20:31:17 -0700135 }
Colin Crossb79aa8f2024-09-25 15:41:01 -0700136 if info.TransitiveText != nil {
137 l.Text.Transitive(info.TransitiveText)
Colin Cross08dca382020-07-21 20:31:17 -0700138 }
Colin Crossb79aa8f2024-09-25 15:41:01 -0700139 if info.TransitiveXML != nil {
140 l.XML.Transitive(info.TransitiveXML)
Colin Cross08dca382020-07-21 20:31:17 -0700141 }
142 return l
143}
144
145func (l LintDepSetsBuilder) Build() LintDepSets {
146 return LintDepSets{
147 HTML: l.HTML.Build(),
148 Text: l.Text.Build(),
149 XML: l.XML.Build(),
150 }
151}
152
Cole Faust69861aa2023-01-31 15:49:07 -0800153type lintDatabaseFiles struct {
154 apiVersionsModule string
155 apiVersionsCopiedName string
156 apiVersionsPrebuiltPath string
157 annotationsModule string
158 annotationCopiedName string
159 annotationPrebuiltpath string
160}
161
162var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{
163 android.SdkPublic: {
164 apiVersionsModule: "api_versions_public",
165 apiVersionsCopiedName: "api_versions_public.xml",
166 apiVersionsPrebuiltPath: "prebuilts/sdk/current/public/data/api-versions.xml",
167 annotationsModule: "sdk-annotations.zip",
168 annotationCopiedName: "annotations-public.zip",
169 annotationPrebuiltpath: "prebuilts/sdk/current/public/data/annotations.zip",
170 },
171 android.SdkSystem: {
172 apiVersionsModule: "api_versions_system",
173 apiVersionsCopiedName: "api_versions_system.xml",
174 apiVersionsPrebuiltPath: "prebuilts/sdk/current/system/data/api-versions.xml",
175 annotationsModule: "sdk-annotations-system.zip",
176 annotationCopiedName: "annotations-system.zip",
177 annotationPrebuiltpath: "prebuilts/sdk/current/system/data/annotations.zip",
178 },
179 android.SdkModule: {
180 apiVersionsModule: "api_versions_module_lib",
181 apiVersionsCopiedName: "api_versions_module_lib.xml",
182 apiVersionsPrebuiltPath: "prebuilts/sdk/current/module-lib/data/api-versions.xml",
183 annotationsModule: "sdk-annotations-module-lib.zip",
184 annotationCopiedName: "annotations-module-lib.zip",
185 annotationPrebuiltpath: "prebuilts/sdk/current/module-lib/data/annotations.zip",
186 },
187 android.SdkSystemServer: {
188 apiVersionsModule: "api_versions_system_server",
189 apiVersionsCopiedName: "api_versions_system_server.xml",
190 apiVersionsPrebuiltPath: "prebuilts/sdk/current/system-server/data/api-versions.xml",
191 annotationsModule: "sdk-annotations-system-server.zip",
192 annotationCopiedName: "annotations-system-server.zip",
193 annotationPrebuiltpath: "prebuilts/sdk/current/system-server/data/annotations.zip",
194 },
195}
196
Spandan Das17854f52022-01-14 21:19:14 +0000197func (l *linter) GetStrictUpdatabilityLinting() bool {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700198 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
199}
200
Spandan Das17854f52022-01-14 21:19:14 +0000201func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700202 l.properties.Lint.Strict_updatability_linting = &strictLinting
203}
204
Spandan Das17854f52022-01-14 21:19:14 +0000205var _ LintDepSetsIntf = (*linter)(nil)
Colin Cross08dca382020-07-21 20:31:17 -0700206
Colin Crossb79aa8f2024-09-25 15:41:01 -0700207var LintProvider = blueprint.NewProvider[*LintInfo]()
Colin Crossc0efd1d2020-07-03 11:56:24 -0700208
Colin Crossb79aa8f2024-09-25 15:41:01 -0700209type LintInfo struct {
210 HTML android.Path
211 Text android.Path
212 XML android.Path
213 ReferenceBaseline android.Path
214
215 TransitiveHTML *android.DepSet[android.Path]
216 TransitiveText *android.DepSet[android.Path]
217 TransitiveXML *android.DepSet[android.Path]
Colin Cross014489c2020-06-02 20:09:13 -0700218}
219
220func (l *linter) enabled() bool {
221 return BoolDefault(l.properties.Lint.Enabled, true)
222}
223
Colin Cross92e4b462020-06-18 15:56:48 -0700224func (l *linter) deps(ctx android.BottomUpMutatorContext) {
225 if !l.enabled() {
226 return
227 }
228
Colin Cross988dfcc2020-07-16 17:32:17 -0700229 extraCheckModules := l.properties.Lint.Extra_check_modules
230
mattgilbridee17645f2022-11-18 18:20:20 +0000231 if extraCheckModulesEnv := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); extraCheckModulesEnv != "" {
232 extraCheckModules = append(extraCheckModules, strings.Split(extraCheckModulesEnv, ",")...)
Colin Cross988dfcc2020-07-16 17:32:17 -0700233 }
234
235 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
236 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700237}
238
Colin Crossad22bc22021-03-10 09:45:40 -0800239// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
240// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800241type lintPaths struct {
242 projectXML android.WritablePath
243 configXML android.WritablePath
244 cacheDir android.WritablePath
245 homeDir android.WritablePath
246 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800247}
248
Colin Cross9b93af42021-03-10 10:40:58 -0800249func lintRBEExecStrategy(ctx android.ModuleContext) string {
250 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
251}
252
Colin Cross62695b92022-08-12 16:09:24 -0700253func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800254 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700255 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800256 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
257 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
258 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700259
Colin Cross1661aff2021-03-12 17:56:51 -0800260 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700261 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
262
263 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700264 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700265 FlagWithOutput("--project_out ", projectXMLPath).
266 FlagWithOutput("--config_out ", configXMLPath).
267 FlagWithArg("--name ", ctx.ModuleName())
268
269 if l.library {
270 cmd.Flag("--library")
271 }
Cole Faustd57e8b22022-08-11 11:59:04 -0700272 if proptools.BoolDefault(l.properties.Lint.Test, false) {
Colin Cross014489c2020-06-02 20:09:13 -0700273 cmd.Flag("--test")
274 }
275 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700276 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700277 }
278 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700279 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700280 }
281
Colin Cross5bedfa22021-03-23 17:07:14 -0700282 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
283 // lint separately.
Colin Cross62695b92022-08-12 16:09:24 -0700284 cmd.FlagWithInput("--srcs ", srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700285
286 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700287
Colin Cross5bedfa22021-03-23 17:07:14 -0700288 if len(l.resources) > 0 {
289 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
290 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700291 }
292
293 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700294 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700295 }
296
Colin Cross5bedfa22021-03-23 17:07:14 -0700297 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700298
Colin Cross5bedfa22021-03-23 17:07:14 -0700299 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700300
Colin Cross1661aff2021-03-12 17:56:51 -0800301 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700302
303 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
304 // the root dir is not set.
305 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700306
307 cmd.FlagWithInput("@",
308 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
309
Cole Faust028b94c2024-01-16 17:17:11 -0800310 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700311 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
312 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
313 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
314 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
315
Cole Faust75dd41b2024-02-05 19:37:05 +0000316 if l.GetStrictUpdatabilityLinting() {
Cole Faust24e25c02024-01-19 14:12:17 -0800317 // Verify the module does not baseline issues that endanger safe updatability.
318 if l.properties.Lint.Baseline_filename != nil {
319 cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
320 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
321 }
322 }
Jaewoong Jung48de8832021-04-21 16:17:25 -0700323
Colin Cross31972dc2021-03-04 10:44:12 -0800324 return lintPaths{
325 projectXML: projectXMLPath,
326 configXML: configXMLPath,
327 cacheDir: cacheDir,
328 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800329 }
330
Colin Cross014489c2020-06-02 20:09:13 -0700331}
332
Liz Kammer20ebfb42020-07-28 11:32:07 -0700333// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700334// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800335func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700336 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
337
338 rule.Command().Text("(").
339 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
340 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
341 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Zi Wange1166f02023-11-06 11:43:17 -0800342 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
343 l.minSdkVersion.String(), l.targetSdkVersion.String()).
Colin Cross014489c2020-06-02 20:09:13 -0700344 Text(`echo "</manifest>"`).
345 Text(") >").Output(manifestPath)
346
347 return manifestPath
348}
349
350func (l *linter) lint(ctx android.ModuleContext) {
351 if !l.enabled() {
352 return
353 }
354
Cole Faust5d0aaf42024-01-29 13:49:14 -0800355 for _, flag := range l.properties.Lint.Flags {
356 if strings.Contains(flag, "--disable") || strings.Contains(flag, "--enable") || strings.Contains(flag, "--check") {
357 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")
358 }
359 }
360
Zi Wange1166f02023-11-06 11:43:17 -0800361 if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700362 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
Orion Hodsonb8166522022-08-15 20:23:38 +0100363 // Skip lint warning checks for NewApi warnings for libcore where they come from source
364 // files that reference the API they are adding (b/208656169).
Orion Hodsonb2d3c8c2022-10-25 16:45:14 +0100365 if !strings.HasPrefix(ctx.ModuleDir(), "libcore") {
Orion Hodsonb8166522022-08-15 20:23:38 +0100366 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
367
368 if len(filtered) != 0 {
369 ctx.PropertyErrorf("lint.warning_checks",
370 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
371 }
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700372 }
Orion Hodsonb8166522022-08-15 20:23:38 +0100373
374 _, filtered := android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700375 if len(filtered) != 0 {
376 ctx.PropertyErrorf("lint.disabled_checks",
377 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
378 }
Cole Faust3f646262022-06-29 14:58:03 -0700379
380 // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
381 if ctx.ModuleName() == "PermissionController" {
382 l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
383 return s != "NewApi"
384 })
385 l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
386 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000387 }
388
Colin Cross92e4b462020-06-18 15:56:48 -0700389 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
390 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Cross313aa542023-12-13 13:47:44 -0800391 if dep, ok := android.OtherModuleProvider(ctx, extraLintCheckModule, JavaInfoProvider); ok {
Colin Crossdcf71b22021-02-01 13:59:03 -0800392 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700393 } else {
394 ctx.PropertyErrorf("lint.extra_check_modules",
395 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
396 }
397 }
398
mattgilbride5aecabe2022-11-29 20:16:36 +0000399 l.extraLintCheckJars = append(l.extraLintCheckJars, android.PathForSource(ctx,
400 "prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar"))
401
Colin Cross1661aff2021-03-12 17:56:51 -0800402 rule := android.NewRuleBuilder(pctx, ctx).
403 Sbox(android.PathForModuleOut(ctx, "lint"),
404 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
405 SandboxInputs()
406
407 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
408 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
409 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
410 rule.Rewrapper(&remoteexec.REParams{
411 Labels: map[string]string{"type": "tool", "name": "lint"},
412 ExecStrategy: lintRBEExecStrategy(ctx),
413 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700414 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800415 })
416 }
Colin Cross014489c2020-06-02 20:09:13 -0700417
418 if l.manifest == nil {
419 manifest := l.generateManifest(ctx, rule)
420 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800421 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700422 }
423
Colin Cross62695b92022-08-12 16:09:24 -0700424 srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
425 srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
Cole Faustdf1efd72023-12-08 12:27:24 -0800426 rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList).Implicits(l.compile_data)
Colin Cross62695b92022-08-12 16:09:24 -0700427
428 lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700429
Colin Cross1661aff2021-03-12 17:56:51 -0800430 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
431 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
432 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Cole Faustdf38f7a2023-03-02 16:43:15 -0800433 referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700434
Colin Cross08dca382020-07-21 20:31:17 -0700435 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700436
437 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Crossb79aa8f2024-09-25 15:41:01 -0700438 if info, ok := android.OtherModuleProvider(ctx, dep, LintProvider); ok {
439 depSetsBuilder.Transitive(info)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700440 }
441 })
Colin Cross014489c2020-06-02 20:09:13 -0700442
Colin Crossb79aa8f2024-09-25 15:41:01 -0700443 depSets := depSetsBuilder.Build()
444
Colin Cross31972dc2021-03-04 10:44:12 -0800445 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
446 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800447 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700448
Cole Faust69861aa2023-01-31 15:49:07 -0800449 files, ok := allLintDatabasefiles[l.compileSdkKind]
450 if !ok {
451 files = allLintDatabasefiles[android.SdkPublic]
Pedro Loureiro18233a22021-06-08 18:11:21 +0000452 }
Colin Cross8a6ed372020-07-06 11:45:51 -0700453 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900454 if ctx.Config().AlwaysUsePrebuiltSdks() {
Cole Faust69861aa2023-01-31 15:49:07 -0800455 annotationsZipPath = android.PathForSource(ctx, files.annotationPrebuiltpath)
456 apiVersionsXMLPath = android.PathForSource(ctx, files.apiVersionsPrebuiltPath)
Colin Cross8a6ed372020-07-06 11:45:51 -0700457 } else {
Cole Faust69861aa2023-01-31 15:49:07 -0800458 annotationsZipPath = copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName)
459 apiVersionsXMLPath = copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700460 }
461
Colin Cross31972dc2021-03-04 10:44:12 -0800462 cmd := rule.Command()
463
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000464 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800465 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700466 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800467 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
468
Colin Cross1661aff2021-03-12 17:56:51 -0800469 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700470 Flag("--quiet").
Tor Norbyecabafde2023-12-07 21:57:28 +0000471 Flag("--include-aosp-issues").
Colin Cross31972dc2021-03-04 10:44:12 -0800472 FlagWithInput("--project ", lintPaths.projectXML).
473 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700474 FlagWithOutput("--html ", html).
475 FlagWithOutput("--text ", text).
476 FlagWithOutput("--xml ", xml).
Zi Wange1166f02023-11-06 11:43:17 -0800477 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
Colin Cross014489c2020-06-02 20:09:13 -0700478 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
479 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
480 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
Colin Cross62695b92022-08-12 16:09:24 -0700481 Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
Colin Cross014489c2020-06-02 20:09:13 -0700482 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800483 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700484 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700485
Colin Cross1661aff2021-03-12 17:56:51 -0800486 rule.Temporary(lintPaths.projectXML)
487 rule.Temporary(lintPaths.configXML)
488
ThiƩbaud Weksteen9c0dff92023-09-29 10:21:56 +1000489 suppressExitCode := BoolDefault(l.properties.Lint.Suppress_exit_code, false)
490 if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" && !suppressExitCode {
mattgilbrideb597abd2023-03-22 17:44:18 +0000491 cmd.Flag("--exitcode")
492 }
493
Colin Cross988dfcc2020-07-16 17:32:17 -0700494 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
495 cmd.FlagWithArg("--check ", checkOnly)
496 }
497
Cole Faustb765d6b2024-01-04 10:29:27 -0800498 if l.properties.Lint.Baseline_filename != nil {
499 cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000500 }
501
Cole Faustdf38f7a2023-03-02 16:43:15 -0800502 cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
Colin Cross6b76c152021-09-09 09:36:25 -0700503
Colin Cross1b9e6832022-10-11 11:22:24 -0700504 cmd.Text("; EXITCODE=$?; ")
505
506 // The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
507 // export them out of the sandbox. Do this before exiting so that the suggestions exit even after
508 // a fatal error.
509 cmd.BuiltTool("soong_zip").
510 FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
511 FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
512 FlagWithInput("-r ", srcsList)
513
514 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 -0700515
Colin Cross31972dc2021-03-04 10:44:12 -0800516 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700517
Colin Crossee4a8b72021-04-05 18:38:05 -0700518 // The HTML output contains a date, remove it to make the output deterministic.
519 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
520
Colin Crossf1a035e2020-11-16 17:32:30 -0800521 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700522
Colin Crossb79aa8f2024-09-25 15:41:01 -0700523 android.SetProvider(ctx, LintProvider, &LintInfo{
524 HTML: html,
525 Text: text,
526 XML: xml,
527 ReferenceBaseline: referenceBaseline,
Colin Cross014489c2020-06-02 20:09:13 -0700528
Colin Crossb79aa8f2024-09-25 15:41:01 -0700529 TransitiveHTML: depSets.HTML,
530 TransitiveText: depSets.Text,
531 TransitiveXML: depSets.XML,
532 })
Colin Cross014489c2020-06-02 20:09:13 -0700533
Colin Crossc0efd1d2020-07-03 11:56:24 -0700534 if l.buildModuleReportZip {
Colin Crossb79aa8f2024-09-25 15:41:01 -0700535 l.reports = BuildModuleLintReportZips(ctx, depSets)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700536 }
Colin Crossb9176412024-01-05 12:51:25 -0800537
538 // Create a per-module phony target to run the lint check.
539 phonyName := ctx.ModuleName() + "-lint"
540 ctx.Phony(phonyName, xml)
Colin Crossb79aa8f2024-09-25 15:41:01 -0700541
542 ctx.SetOutputFiles(android.Paths{xml}, ".lint")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700543}
Colin Cross014489c2020-06-02 20:09:13 -0700544
Colin Cross08dca382020-07-21 20:31:17 -0700545func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
Colin Crossc85750b2022-04-21 12:50:51 -0700546 htmlList := android.SortedUniquePaths(depSets.HTML.ToList())
547 textList := android.SortedUniquePaths(depSets.Text.ToList())
548 xmlList := android.SortedUniquePaths(depSets.XML.ToList())
Colin Cross08dca382020-07-21 20:31:17 -0700549
550 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
551 return nil
552 }
553
554 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
555 lintZip(ctx, htmlList, htmlZip)
556
557 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
558 lintZip(ctx, textList, textZip)
559
560 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
561 lintZip(ctx, xmlList, xmlZip)
562
563 return android.Paths{htmlZip, textZip, xmlZip}
564}
565
Colin Cross014489c2020-06-02 20:09:13 -0700566type lintSingleton struct {
Cole Faustdf38f7a2023-03-02 16:43:15 -0800567 htmlZip android.WritablePath
568 textZip android.WritablePath
569 xmlZip android.WritablePath
570 referenceBaselineZip android.WritablePath
Colin Cross014489c2020-06-02 20:09:13 -0700571}
572
573func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
574 l.generateLintReportZips(ctx)
575 l.copyLintDependencies(ctx)
576}
577
Pedro Loureiro18233a22021-06-08 18:11:21 +0000578func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
579 var res android.Module
580 ctx.VisitAllModules(func(m android.Module) {
581 if ctx.ModuleName(m) == moduleName {
582 if res == nil {
583 res = m
584 } else {
585 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
586 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
587 }
588 }
589 })
590 return res
591}
592
Colin Cross014489c2020-06-02 20:09:13 -0700593func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900594 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700595 return
596 }
597
Cole Faust69861aa2023-01-31 15:49:07 -0800598 for _, sdk := range android.SortedKeys(allLintDatabasefiles) {
599 files := allLintDatabasefiles[sdk]
600 apiVersionsDb := findModuleOrErr(ctx, files.apiVersionsModule)
601 if apiVersionsDb == nil {
602 if !ctx.Config().AllowMissingDependencies() {
Paul Duffin375acd82024-05-02 12:44:20 +0100603 ctx.Errorf("lint: missing module %s", files.apiVersionsModule)
Cole Faust69861aa2023-01-31 15:49:07 -0800604 }
605 return
Colin Cross014489c2020-06-02 20:09:13 -0700606 }
Colin Cross014489c2020-06-02 20:09:13 -0700607
Cole Faust69861aa2023-01-31 15:49:07 -0800608 sdkAnnotations := findModuleOrErr(ctx, files.annotationsModule)
609 if sdkAnnotations == nil {
610 if !ctx.Config().AllowMissingDependencies() {
Paul Duffin375acd82024-05-02 12:44:20 +0100611 ctx.Errorf("lint: missing module %s", files.annotationsModule)
Cole Faust69861aa2023-01-31 15:49:07 -0800612 }
613 return
Anton Hanssonea17a452022-05-09 09:42:17 +0000614 }
Cole Faust69861aa2023-01-31 15:49:07 -0800615
616 ctx.Build(pctx, android.BuildParams{
617 Rule: android.CpIfChanged,
618 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
619 Output: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
620 })
621
622 ctx.Build(pctx, android.BuildParams{
623 Rule: android.CpIfChanged,
624 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
625 Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
626 })
Anton Hanssonea17a452022-05-09 09:42:17 +0000627 }
Colin Cross014489c2020-06-02 20:09:13 -0700628}
629
Cole Faust69861aa2023-01-31 15:49:07 -0800630func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.WritablePath {
Pedro Loureiro18233a22021-06-08 18:11:21 +0000631 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700632}
633
634func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700635 if ctx.Config().UnbundledBuild() {
636 return
637 }
638
Colin Crossb79aa8f2024-09-25 15:41:01 -0700639 var outputs []*LintInfo
Colin Cross014489c2020-06-02 20:09:13 -0700640 var dirs []string
641 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500642 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700643 return
644 }
645
Colin Cross56a83212020-09-15 18:30:11 -0700646 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
Yu Liu663e4502024-08-12 18:23:59 +0000647 apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
Colin Cross56a83212020-09-15 18:30:11 -0700648 if apexInfo.IsForPlatform() {
649 // There are stray platform variants of modules in apexes that are not available for
650 // the platform, and they sometimes can't be built. Don't depend on them.
651 return
652 }
Colin Cross014489c2020-06-02 20:09:13 -0700653 }
654
Colin Crossb79aa8f2024-09-25 15:41:01 -0700655 if lintInfo, ok := android.OtherModuleProvider(ctx, m, LintProvider); ok {
656 outputs = append(outputs, lintInfo)
Colin Cross014489c2020-06-02 20:09:13 -0700657 }
658 })
659
660 dirs = android.SortedUniqueStrings(dirs)
661
Colin Crossb79aa8f2024-09-25 15:41:01 -0700662 zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) {
Colin Cross014489c2020-06-02 20:09:13 -0700663 var paths android.Paths
664
665 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700666 if p := get(output); p != nil {
667 paths = append(paths, p)
668 }
Colin Cross014489c2020-06-02 20:09:13 -0700669 }
670
Colin Crossc0efd1d2020-07-03 11:56:24 -0700671 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700672 }
673
674 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700675 zip(l.htmlZip, func(l *LintInfo) android.Path { return l.HTML })
Colin Cross014489c2020-06-02 20:09:13 -0700676
677 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700678 zip(l.textZip, func(l *LintInfo) android.Path { return l.Text })
Colin Cross014489c2020-06-02 20:09:13 -0700679
680 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700681 zip(l.xmlZip, func(l *LintInfo) android.Path { return l.XML })
Colin Cross014489c2020-06-02 20:09:13 -0700682
Cole Faustdf38f7a2023-03-02 16:43:15 -0800683 l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip")
Colin Crossb79aa8f2024-09-25 15:41:01 -0700684 zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline })
Cole Faustdf38f7a2023-03-02 16:43:15 -0800685
686 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
Colin Cross014489c2020-06-02 20:09:13 -0700687}
688
689func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700690 if !ctx.Config().UnbundledBuild() {
Cole Faustdf38f7a2023-03-02 16:43:15 -0800691 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
Colin Cross8a6ed372020-07-06 11:45:51 -0700692 }
Colin Cross014489c2020-06-02 20:09:13 -0700693}
694
695var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
696
697func init() {
LaMont Jones0c10e4d2023-05-16 00:58:37 +0000698 android.RegisterParallelSingletonType("lint",
Colin Cross014489c2020-06-02 20:09:13 -0700699 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700700
701 registerLintBuildComponents(android.InitRegistrationContext)
702}
703
704func registerLintBuildComponents(ctx android.RegistrationContext) {
705 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
706 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
707 })
Colin Cross014489c2020-06-02 20:09:13 -0700708}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700709
710func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
711 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
712
713 sort.Slice(paths, func(i, j int) bool {
714 return paths[i].String() < paths[j].String()
715 })
716
Colin Crossf1a035e2020-11-16 17:32:30 -0800717 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700718
Colin Crossf1a035e2020-11-16 17:32:30 -0800719 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700720 FlagWithOutput("-o ", outputPath).
721 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800722 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700723
Colin Crossf1a035e2020-11-16 17:32:30 -0800724 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700725}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700726
727// Enforce the strict updatability linting to all applicable transitive dependencies.
728func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
729 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000730 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700731 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000732 if a, ok := d.(LintDepSetsIntf); ok {
733 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700734 }
735 })
736 }
737}