blob: 931820d7443aa2b6fbb762f9895b366e6717c330 [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"
Cole Fauste5bf3fb2022-07-01 19:39:14 +000020 "strconv"
Colin Cross988dfcc2020-07-16 17:32:17 -070021 "strings"
Colin Cross014489c2020-06-02 20:09:13 -070022
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
59 // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
60 Baseline_filename *string
Jaewoong Jung48de8832021-04-21 16:17:25 -070061
62 // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
63 Strict_updatability_linting *bool
Cole Faustd57e8b22022-08-11 11:59:04 -070064
65 // Treat the code in this module as test code for @VisibleForTesting enforcement.
66 // This will be true by default for test module types, false otherwise.
67 // If soong gets support for testonly, this flag should be replaced with that.
68 Test *bool
Colin Cross014489c2020-06-02 20:09:13 -070069 }
70}
71
72type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000073 name string
74 manifest android.Path
75 mergedManifest android.Path
76 srcs android.Paths
77 srcJars android.Paths
78 resources android.Paths
79 classpath android.Paths
80 classes android.Path
81 extraLintCheckJars android.Paths
Pedro Loureirof4a88b12021-02-25 16:23:22 +000082 library bool
Cole Fauste5bf3fb2022-07-01 19:39:14 +000083 minSdkVersion int
84 targetSdkVersion int
85 compileSdkVersion int
Pedro Loureiro18233a22021-06-08 18:11:21 +000086 compileSdkKind android.SdkKind
Pedro Loureirof4a88b12021-02-25 16:23:22 +000087 javaLanguageLevel string
88 kotlinLanguageLevel string
89 outputs lintOutputs
90 properties LintProperties
91 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070092
Colin Cross08dca382020-07-21 20:31:17 -070093 reports android.Paths
94
Colin Crossc0efd1d2020-07-03 11:56:24 -070095 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070096}
97
98type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070099 html android.Path
100 text android.Path
101 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -0700102
Colin Cross08dca382020-07-21 20:31:17 -0700103 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -0700104}
105
Colin Cross08dca382020-07-21 20:31:17 -0700106type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -0700107 lintOutputs() *lintOutputs
108}
109
Spandan Das17854f52022-01-14 21:19:14 +0000110type LintDepSetsIntf interface {
Colin Cross08dca382020-07-21 20:31:17 -0700111 LintDepSets() LintDepSets
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700112
113 // Methods used to propagate strict_updatability_linting values.
Spandan Das17854f52022-01-14 21:19:14 +0000114 GetStrictUpdatabilityLinting() bool
115 SetStrictUpdatabilityLinting(bool)
Colin Cross08dca382020-07-21 20:31:17 -0700116}
117
118type LintDepSets struct {
119 HTML, Text, XML *android.DepSet
120}
121
122type LintDepSetsBuilder struct {
123 HTML, Text, XML *android.DepSetBuilder
124}
125
126func NewLintDepSetBuilder() LintDepSetsBuilder {
127 return LintDepSetsBuilder{
128 HTML: android.NewDepSetBuilder(android.POSTORDER),
129 Text: android.NewDepSetBuilder(android.POSTORDER),
130 XML: android.NewDepSetBuilder(android.POSTORDER),
131 }
132}
133
134func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
135 l.HTML.Direct(html)
136 l.Text.Direct(text)
137 l.XML.Direct(xml)
138 return l
139}
140
141func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
142 if depSets.HTML != nil {
143 l.HTML.Transitive(depSets.HTML)
144 }
145 if depSets.Text != nil {
146 l.Text.Transitive(depSets.Text)
147 }
148 if depSets.XML != nil {
149 l.XML.Transitive(depSets.XML)
150 }
151 return l
152}
153
154func (l LintDepSetsBuilder) Build() LintDepSets {
155 return LintDepSets{
156 HTML: l.HTML.Build(),
157 Text: l.Text.Build(),
158 XML: l.XML.Build(),
159 }
160}
161
162func (l *linter) LintDepSets() LintDepSets {
163 return l.outputs.depSets
164}
165
Spandan Das17854f52022-01-14 21:19:14 +0000166func (l *linter) GetStrictUpdatabilityLinting() bool {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700167 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
168}
169
Spandan Das17854f52022-01-14 21:19:14 +0000170func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700171 l.properties.Lint.Strict_updatability_linting = &strictLinting
172}
173
Spandan Das17854f52022-01-14 21:19:14 +0000174var _ LintDepSetsIntf = (*linter)(nil)
Colin Cross08dca382020-07-21 20:31:17 -0700175
176var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700177
178func (l *linter) lintOutputs() *lintOutputs {
179 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700180}
181
182func (l *linter) enabled() bool {
183 return BoolDefault(l.properties.Lint.Enabled, true)
184}
185
Colin Cross92e4b462020-06-18 15:56:48 -0700186func (l *linter) deps(ctx android.BottomUpMutatorContext) {
187 if !l.enabled() {
188 return
189 }
190
Colin Cross988dfcc2020-07-16 17:32:17 -0700191 extraCheckModules := l.properties.Lint.Extra_check_modules
192
193 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
194 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
195 extraCheckModules = strings.Split(checkOnlyModules, ",")
196 }
197 }
198
199 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
200 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700201}
202
Colin Crossad22bc22021-03-10 09:45:40 -0800203// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
204// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800205type lintPaths struct {
206 projectXML android.WritablePath
207 configXML android.WritablePath
208 cacheDir android.WritablePath
209 homeDir android.WritablePath
210 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800211}
212
Colin Cross9b93af42021-03-10 10:40:58 -0800213func lintRBEExecStrategy(ctx android.ModuleContext) string {
214 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
215}
216
Colin Cross62695b92022-08-12 16:09:24 -0700217func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800218 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700219 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800220 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
221 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
222 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700223
Colin Cross1661aff2021-03-12 17:56:51 -0800224 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700225 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
226
227 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700228 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700229 FlagWithOutput("--project_out ", projectXMLPath).
230 FlagWithOutput("--config_out ", configXMLPath).
231 FlagWithArg("--name ", ctx.ModuleName())
232
233 if l.library {
234 cmd.Flag("--library")
235 }
Cole Faustd57e8b22022-08-11 11:59:04 -0700236 if proptools.BoolDefault(l.properties.Lint.Test, false) {
Colin Cross014489c2020-06-02 20:09:13 -0700237 cmd.Flag("--test")
238 }
239 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700240 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700241 }
242 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700243 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700244 }
245
Colin Cross5bedfa22021-03-23 17:07:14 -0700246 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
247 // lint separately.
Colin Cross62695b92022-08-12 16:09:24 -0700248 cmd.FlagWithInput("--srcs ", srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700249
250 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700251
Colin Cross5bedfa22021-03-23 17:07:14 -0700252 if len(l.resources) > 0 {
253 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
254 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700255 }
256
257 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700258 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700259 }
260
Colin Cross5bedfa22021-03-23 17:07:14 -0700261 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700262
Colin Cross5bedfa22021-03-23 17:07:14 -0700263 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700264
Colin Cross1661aff2021-03-12 17:56:51 -0800265 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700266
267 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
268 // the root dir is not set.
269 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700270
271 cmd.FlagWithInput("@",
272 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
273
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000274 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700275 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
276 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
277 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
278 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
279
Spandan Das17854f52022-01-14 21:19:14 +0000280 if l.GetStrictUpdatabilityLinting() {
Jaewoong Jung3c87b1d2021-04-22 11:01:36 -0700281 // Verify the module does not baseline issues that endanger safe updatability.
Jaewoong Jung48de8832021-04-21 16:17:25 -0700282 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
283 cmd.FlagWithInput("--baseline ", baselinePath.Path())
284 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
285 }
286 }
287
Colin Cross31972dc2021-03-04 10:44:12 -0800288 return lintPaths{
289 projectXML: projectXMLPath,
290 configXML: configXMLPath,
291 cacheDir: cacheDir,
292 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800293 }
294
Colin Cross014489c2020-06-02 20:09:13 -0700295}
296
Liz Kammer20ebfb42020-07-28 11:32:07 -0700297// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700298// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800299func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700300 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
301
302 rule.Command().Text("(").
303 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
304 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
305 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000306 Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
307 l.minSdkVersion, l.targetSdkVersion).
Colin Cross014489c2020-06-02 20:09:13 -0700308 Text(`echo "</manifest>"`).
309 Text(") >").Output(manifestPath)
310
311 return manifestPath
312}
313
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700314func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
315 var lintBaseline android.OptionalPath
316 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
317 if String(l.properties.Lint.Baseline_filename) != "" {
318 // if manually specified, we require the file to exist
319 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
320 } else {
321 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
322 }
323 }
324 return lintBaseline
325}
326
Colin Cross014489c2020-06-02 20:09:13 -0700327func (l *linter) lint(ctx android.ModuleContext) {
328 if !l.enabled() {
329 return
330 }
331
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000332 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700333 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
Orion Hodsonb8166522022-08-15 20:23:38 +0100334 // Skip lint warning checks for NewApi warnings for libcore where they come from source
335 // files that reference the API they are adding (b/208656169).
336 if ctx.ModuleDir() != "libcore" {
337 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
338
339 if len(filtered) != 0 {
340 ctx.PropertyErrorf("lint.warning_checks",
341 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
342 }
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700343 }
Orion Hodsonb8166522022-08-15 20:23:38 +0100344
345 _, filtered := android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700346 if len(filtered) != 0 {
347 ctx.PropertyErrorf("lint.disabled_checks",
348 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
349 }
Cole Faust3f646262022-06-29 14:58:03 -0700350
351 // TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
352 if ctx.ModuleName() == "PermissionController" {
353 l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
354 return s != "NewApi"
355 })
356 l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
357 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000358 }
359
Colin Cross92e4b462020-06-18 15:56:48 -0700360 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
361 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800362 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
363 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
364 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700365 } else {
366 ctx.PropertyErrorf("lint.extra_check_modules",
367 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
368 }
369 }
370
Colin Cross1661aff2021-03-12 17:56:51 -0800371 rule := android.NewRuleBuilder(pctx, ctx).
372 Sbox(android.PathForModuleOut(ctx, "lint"),
373 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
374 SandboxInputs()
375
376 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
377 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
378 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
379 rule.Rewrapper(&remoteexec.REParams{
380 Labels: map[string]string{"type": "tool", "name": "lint"},
381 ExecStrategy: lintRBEExecStrategy(ctx),
382 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700383 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800384 })
385 }
Colin Cross014489c2020-06-02 20:09:13 -0700386
387 if l.manifest == nil {
388 manifest := l.generateManifest(ctx, rule)
389 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800390 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700391 }
392
Colin Cross62695b92022-08-12 16:09:24 -0700393 srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
394 srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
395 rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList)
396
397 lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700398
Colin Cross1661aff2021-03-12 17:56:51 -0800399 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
400 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
401 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Cross6b76c152021-09-09 09:36:25 -0700402 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700403
Colin Cross08dca382020-07-21 20:31:17 -0700404 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700405
406 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000407 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700408 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700409 }
410 })
Colin Cross014489c2020-06-02 20:09:13 -0700411
Colin Cross31972dc2021-03-04 10:44:12 -0800412 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
413 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800414 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700415
Pedro Loureiro18233a22021-06-08 18:11:21 +0000416 var apiVersionsName, apiVersionsPrebuilt string
Pedro Loureiroffb643f2021-07-05 13:53:36 +0000417 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
418 // When compiling an SDK module (or system server) we use the filtered
419 // database because otherwise lint's
Pedro Loureiro18233a22021-06-08 18:11:21 +0000420 // NewApi check produces too many false positives; This database excludes information
421 // about classes created in mainline modules hence removing those false positives.
422 apiVersionsName = "api_versions_public_filtered.xml"
423 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
424 } else {
425 apiVersionsName = "api_versions.xml"
426 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
427 }
428
Colin Cross8a6ed372020-07-06 11:45:51 -0700429 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900430 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700431 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
Pedro Loureiro18233a22021-06-08 18:11:21 +0000432 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
Colin Cross8a6ed372020-07-06 11:45:51 -0700433 } else {
434 annotationsZipPath = copiedAnnotationsZipPath(ctx)
Pedro Loureiro18233a22021-06-08 18:11:21 +0000435 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700436 }
437
Colin Cross31972dc2021-03-04 10:44:12 -0800438 cmd := rule.Command()
439
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000440 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800441 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700442 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800443 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
444
Colin Cross1661aff2021-03-12 17:56:51 -0800445 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700446 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800447 FlagWithInput("--project ", lintPaths.projectXML).
448 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700449 FlagWithOutput("--html ", html).
450 FlagWithOutput("--text ", text).
451 FlagWithOutput("--xml ", xml).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000452 FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
Colin Cross014489c2020-06-02 20:09:13 -0700453 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
454 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
455 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
456 Flag("--exitcode").
Colin Cross62695b92022-08-12 16:09:24 -0700457 Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
Colin Cross014489c2020-06-02 20:09:13 -0700458 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800459 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700460 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700461
Colin Cross1661aff2021-03-12 17:56:51 -0800462 rule.Temporary(lintPaths.projectXML)
463 rule.Temporary(lintPaths.configXML)
464
Colin Cross988dfcc2020-07-16 17:32:17 -0700465 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
466 cmd.FlagWithArg("--check ", checkOnly)
467 }
468
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700469 lintBaseline := l.getBaselineFilepath(ctx)
470 if lintBaseline.Valid() {
471 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000472 }
473
Colin Cross6b76c152021-09-09 09:36:25 -0700474 cmd.FlagWithOutput("--write-reference-baseline ", baseline)
475
Colin Cross31972dc2021-03-04 10:44:12 -0800476 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700477
Colin Cross31972dc2021-03-04 10:44:12 -0800478 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700479
Colin Crossee4a8b72021-04-05 18:38:05 -0700480 // The HTML output contains a date, remove it to make the output deterministic.
481 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
482
Colin Cross62695b92022-08-12 16:09:24 -0700483 // The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
484 // export them out of the sandbox.
485 rule.Command().BuiltTool("soong_zip").
486 FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
487 FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
488 FlagWithInput("-r ", srcsList)
489
Colin Crossf1a035e2020-11-16 17:32:30 -0800490 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700491
Colin Crossc0efd1d2020-07-03 11:56:24 -0700492 l.outputs = lintOutputs{
493 html: html,
494 text: text,
495 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700496
Colin Cross08dca382020-07-21 20:31:17 -0700497 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700498 }
Colin Cross014489c2020-06-02 20:09:13 -0700499
Colin Crossc0efd1d2020-07-03 11:56:24 -0700500 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700501 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700502 }
503}
Colin Cross014489c2020-06-02 20:09:13 -0700504
Colin Cross08dca382020-07-21 20:31:17 -0700505func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
506 htmlList := depSets.HTML.ToSortedList()
507 textList := depSets.Text.ToSortedList()
508 xmlList := depSets.XML.ToSortedList()
509
510 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
511 return nil
512 }
513
514 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
515 lintZip(ctx, htmlList, htmlZip)
516
517 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
518 lintZip(ctx, textList, textZip)
519
520 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
521 lintZip(ctx, xmlList, xmlZip)
522
523 return android.Paths{htmlZip, textZip, xmlZip}
524}
525
Colin Cross014489c2020-06-02 20:09:13 -0700526type lintSingleton struct {
527 htmlZip android.WritablePath
528 textZip android.WritablePath
529 xmlZip android.WritablePath
530}
531
532func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
533 l.generateLintReportZips(ctx)
534 l.copyLintDependencies(ctx)
535}
536
Pedro Loureiro18233a22021-06-08 18:11:21 +0000537func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
538 var res android.Module
539 ctx.VisitAllModules(func(m android.Module) {
540 if ctx.ModuleName(m) == moduleName {
541 if res == nil {
542 res = m
543 } else {
544 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
545 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
546 }
547 }
548 })
549 return res
550}
551
Colin Cross014489c2020-06-02 20:09:13 -0700552func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900553 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700554 return
555 }
556
Anton Hansson67cf60e2022-05-09 09:36:22 +0000557 apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
558 if apiVersionsDb == nil {
Colin Cross014489c2020-06-02 20:09:13 -0700559 if !ctx.Config().AllowMissingDependencies() {
Anton Hansson67cf60e2022-05-09 09:36:22 +0000560 ctx.Errorf("lint: missing module api_versions_public")
Colin Cross014489c2020-06-02 20:09:13 -0700561 }
562 return
563 }
564
Anton Hanssonea17a452022-05-09 09:42:17 +0000565 sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
566 if sdkAnnotations == nil {
567 if !ctx.Config().AllowMissingDependencies() {
568 ctx.Errorf("lint: missing module sdk-annotations.zip")
569 }
570 return
571 }
572
Pedro Loureiro18233a22021-06-08 18:11:21 +0000573 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
574 if filteredDb == nil {
575 if !ctx.Config().AllowMissingDependencies() {
576 ctx.Errorf("lint: missing api-versions-xml-public-filtered")
577 }
578 return
579 }
580
Colin Cross014489c2020-06-02 20:09:13 -0700581 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800582 Rule: android.CpIfChanged,
Anton Hanssonea17a452022-05-09 09:42:17 +0000583 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
Colin Cross8a6ed372020-07-06 11:45:51 -0700584 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700585 })
586
587 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800588 Rule: android.CpIfChanged,
Anton Hansson67cf60e2022-05-09 09:36:22 +0000589 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
Pedro Loureiro18233a22021-06-08 18:11:21 +0000590 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
591 })
592
593 ctx.Build(pctx, android.BuildParams{
594 Rule: android.CpIfChanged,
595 Input: android.OutputFileForModule(ctx, filteredDb, ""),
596 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
Colin Cross014489c2020-06-02 20:09:13 -0700597 })
598}
599
Colin Cross8a6ed372020-07-06 11:45:51 -0700600func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700601 return android.PathForOutput(ctx, "lint", "annotations.zip")
602}
603
Pedro Loureiro18233a22021-06-08 18:11:21 +0000604func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
605 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700606}
607
608func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700609 if ctx.Config().UnbundledBuild() {
610 return
611 }
612
Colin Cross014489c2020-06-02 20:09:13 -0700613 var outputs []*lintOutputs
614 var dirs []string
615 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500616 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700617 return
618 }
619
Colin Cross56a83212020-09-15 18:30:11 -0700620 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
621 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
622 if apexInfo.IsForPlatform() {
623 // There are stray platform variants of modules in apexes that are not available for
624 // the platform, and they sometimes can't be built. Don't depend on them.
625 return
626 }
Colin Cross014489c2020-06-02 20:09:13 -0700627 }
628
Colin Cross08dca382020-07-21 20:31:17 -0700629 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700630 outputs = append(outputs, l.lintOutputs())
631 }
632 })
633
634 dirs = android.SortedUniqueStrings(dirs)
635
636 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
637 var paths android.Paths
638
639 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700640 if p := get(output); p != nil {
641 paths = append(paths, p)
642 }
Colin Cross014489c2020-06-02 20:09:13 -0700643 }
644
Colin Crossc0efd1d2020-07-03 11:56:24 -0700645 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700646 }
647
648 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
649 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
650
651 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
652 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
653
654 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
655 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
656
657 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
658}
659
660func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700661 if !ctx.Config().UnbundledBuild() {
662 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
663 }
Colin Cross014489c2020-06-02 20:09:13 -0700664}
665
666var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
667
668func init() {
669 android.RegisterSingletonType("lint",
670 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700671
672 registerLintBuildComponents(android.InitRegistrationContext)
673}
674
675func registerLintBuildComponents(ctx android.RegistrationContext) {
676 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
677 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
678 })
Colin Cross014489c2020-06-02 20:09:13 -0700679}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700680
681func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
682 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
683
684 sort.Slice(paths, func(i, j int) bool {
685 return paths[i].String() < paths[j].String()
686 })
687
Colin Crossf1a035e2020-11-16 17:32:30 -0800688 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700689
Colin Crossf1a035e2020-11-16 17:32:30 -0800690 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700691 FlagWithOutput("-o ", outputPath).
692 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800693 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700694
Colin Crossf1a035e2020-11-16 17:32:30 -0800695 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700696}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700697
698// Enforce the strict updatability linting to all applicable transitive dependencies.
699func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
700 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000701 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700702 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000703 if a, ok := d.(LintDepSetsIntf); ok {
704 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700705 }
706 })
707 }
708}