blob: 5808e0d0cc6acfc9ce5870437bcfa30f88ac8186 [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
Colin Cross014489c2020-06-02 20:09:13 -070064 }
65}
66
67type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000068 name string
69 manifest android.Path
70 mergedManifest android.Path
71 srcs android.Paths
72 srcJars android.Paths
73 resources android.Paths
74 classpath android.Paths
75 classes android.Path
76 extraLintCheckJars android.Paths
77 test bool
78 library bool
Cole Fauste5bf3fb2022-07-01 19:39:14 +000079 minSdkVersion int
80 targetSdkVersion int
81 compileSdkVersion int
Pedro Loureiro18233a22021-06-08 18:11:21 +000082 compileSdkKind android.SdkKind
Pedro Loureirof4a88b12021-02-25 16:23:22 +000083 javaLanguageLevel string
84 kotlinLanguageLevel string
85 outputs lintOutputs
86 properties LintProperties
87 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070088
Colin Cross08dca382020-07-21 20:31:17 -070089 reports android.Paths
90
Colin Crossc0efd1d2020-07-03 11:56:24 -070091 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070092}
93
94type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070095 html android.Path
96 text android.Path
97 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070098
Colin Cross08dca382020-07-21 20:31:17 -070099 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -0700100}
101
Colin Cross08dca382020-07-21 20:31:17 -0700102type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -0700103 lintOutputs() *lintOutputs
104}
105
Spandan Das17854f52022-01-14 21:19:14 +0000106type LintDepSetsIntf interface {
Colin Cross08dca382020-07-21 20:31:17 -0700107 LintDepSets() LintDepSets
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700108
109 // Methods used to propagate strict_updatability_linting values.
Spandan Das17854f52022-01-14 21:19:14 +0000110 GetStrictUpdatabilityLinting() bool
111 SetStrictUpdatabilityLinting(bool)
Colin Cross08dca382020-07-21 20:31:17 -0700112}
113
114type LintDepSets struct {
115 HTML, Text, XML *android.DepSet
116}
117
118type LintDepSetsBuilder struct {
119 HTML, Text, XML *android.DepSetBuilder
120}
121
122func NewLintDepSetBuilder() LintDepSetsBuilder {
123 return LintDepSetsBuilder{
124 HTML: android.NewDepSetBuilder(android.POSTORDER),
125 Text: android.NewDepSetBuilder(android.POSTORDER),
126 XML: android.NewDepSetBuilder(android.POSTORDER),
127 }
128}
129
130func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
131 l.HTML.Direct(html)
132 l.Text.Direct(text)
133 l.XML.Direct(xml)
134 return l
135}
136
137func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
138 if depSets.HTML != nil {
139 l.HTML.Transitive(depSets.HTML)
140 }
141 if depSets.Text != nil {
142 l.Text.Transitive(depSets.Text)
143 }
144 if depSets.XML != nil {
145 l.XML.Transitive(depSets.XML)
146 }
147 return l
148}
149
150func (l LintDepSetsBuilder) Build() LintDepSets {
151 return LintDepSets{
152 HTML: l.HTML.Build(),
153 Text: l.Text.Build(),
154 XML: l.XML.Build(),
155 }
156}
157
158func (l *linter) LintDepSets() LintDepSets {
159 return l.outputs.depSets
160}
161
Spandan Das17854f52022-01-14 21:19:14 +0000162func (l *linter) GetStrictUpdatabilityLinting() bool {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700163 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
164}
165
Spandan Das17854f52022-01-14 21:19:14 +0000166func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700167 l.properties.Lint.Strict_updatability_linting = &strictLinting
168}
169
Spandan Das17854f52022-01-14 21:19:14 +0000170var _ LintDepSetsIntf = (*linter)(nil)
Colin Cross08dca382020-07-21 20:31:17 -0700171
172var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700173
174func (l *linter) lintOutputs() *lintOutputs {
175 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700176}
177
178func (l *linter) enabled() bool {
179 return BoolDefault(l.properties.Lint.Enabled, true)
180}
181
Colin Cross92e4b462020-06-18 15:56:48 -0700182func (l *linter) deps(ctx android.BottomUpMutatorContext) {
183 if !l.enabled() {
184 return
185 }
186
Colin Cross988dfcc2020-07-16 17:32:17 -0700187 extraCheckModules := l.properties.Lint.Extra_check_modules
188
189 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
190 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
191 extraCheckModules = strings.Split(checkOnlyModules, ",")
192 }
193 }
194
195 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
196 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700197}
198
Colin Crossad22bc22021-03-10 09:45:40 -0800199// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
200// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800201type lintPaths struct {
202 projectXML android.WritablePath
203 configXML android.WritablePath
204 cacheDir android.WritablePath
205 homeDir android.WritablePath
206 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800207}
208
Colin Cross9b93af42021-03-10 10:40:58 -0800209func lintRBEExecStrategy(ctx android.ModuleContext) string {
210 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
211}
212
Colin Cross62695b92022-08-12 16:09:24 -0700213func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800214 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700215 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800216 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
217 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
218 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700219
Colin Cross1661aff2021-03-12 17:56:51 -0800220 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700221 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
222
223 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700224 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700225 FlagWithOutput("--project_out ", projectXMLPath).
226 FlagWithOutput("--config_out ", configXMLPath).
227 FlagWithArg("--name ", ctx.ModuleName())
228
229 if l.library {
230 cmd.Flag("--library")
231 }
232 if l.test {
233 cmd.Flag("--test")
234 }
235 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700236 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700237 }
238 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700239 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700240 }
241
Colin Cross5bedfa22021-03-23 17:07:14 -0700242 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
243 // lint separately.
Colin Cross62695b92022-08-12 16:09:24 -0700244 cmd.FlagWithInput("--srcs ", srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700245
246 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700247
Colin Cross5bedfa22021-03-23 17:07:14 -0700248 if len(l.resources) > 0 {
249 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
250 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700251 }
252
253 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700254 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700255 }
256
Colin Cross5bedfa22021-03-23 17:07:14 -0700257 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700258
Colin Cross5bedfa22021-03-23 17:07:14 -0700259 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700260
Colin Cross1661aff2021-03-12 17:56:51 -0800261 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700262
263 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
264 // the root dir is not set.
265 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700266
267 cmd.FlagWithInput("@",
268 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
269
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000270 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700271 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
272 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
273 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
274 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
275
Spandan Das17854f52022-01-14 21:19:14 +0000276 if l.GetStrictUpdatabilityLinting() {
Jaewoong Jung3c87b1d2021-04-22 11:01:36 -0700277 // Verify the module does not baseline issues that endanger safe updatability.
Jaewoong Jung48de8832021-04-21 16:17:25 -0700278 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
279 cmd.FlagWithInput("--baseline ", baselinePath.Path())
280 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
281 }
282 }
283
Colin Cross31972dc2021-03-04 10:44:12 -0800284 return lintPaths{
285 projectXML: projectXMLPath,
286 configXML: configXMLPath,
287 cacheDir: cacheDir,
288 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800289 }
290
Colin Cross014489c2020-06-02 20:09:13 -0700291}
292
Liz Kammer20ebfb42020-07-28 11:32:07 -0700293// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700294// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800295func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700296 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
297
298 rule.Command().Text("(").
299 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
300 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
301 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000302 Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
303 l.minSdkVersion, l.targetSdkVersion).
Colin Cross014489c2020-06-02 20:09:13 -0700304 Text(`echo "</manifest>"`).
305 Text(") >").Output(manifestPath)
306
307 return manifestPath
308}
309
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700310func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
311 var lintBaseline android.OptionalPath
312 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
313 if String(l.properties.Lint.Baseline_filename) != "" {
314 // if manually specified, we require the file to exist
315 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
316 } else {
317 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
318 }
319 }
320 return lintBaseline
321}
322
Colin Cross014489c2020-06-02 20:09:13 -0700323func (l *linter) lint(ctx android.ModuleContext) {
324 if !l.enabled() {
325 return
326 }
327
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000328 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700329 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
330 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
331 if len(filtered) != 0 {
332 ctx.PropertyErrorf("lint.warning_checks",
333 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
334 }
335 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
336 if len(filtered) != 0 {
337 ctx.PropertyErrorf("lint.disabled_checks",
338 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
339 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000340 }
341
Colin Cross92e4b462020-06-18 15:56:48 -0700342 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
343 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800344 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
345 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
346 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700347 } else {
348 ctx.PropertyErrorf("lint.extra_check_modules",
349 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
350 }
351 }
352
Colin Cross1661aff2021-03-12 17:56:51 -0800353 rule := android.NewRuleBuilder(pctx, ctx).
354 Sbox(android.PathForModuleOut(ctx, "lint"),
355 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
356 SandboxInputs()
357
358 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
359 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
360 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
361 rule.Rewrapper(&remoteexec.REParams{
362 Labels: map[string]string{"type": "tool", "name": "lint"},
363 ExecStrategy: lintRBEExecStrategy(ctx),
364 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700365 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800366 })
367 }
Colin Cross014489c2020-06-02 20:09:13 -0700368
369 if l.manifest == nil {
370 manifest := l.generateManifest(ctx, rule)
371 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800372 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700373 }
374
Colin Cross62695b92022-08-12 16:09:24 -0700375 srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
376 srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
377 rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList)
378
379 lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700380
Colin Cross1661aff2021-03-12 17:56:51 -0800381 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
382 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
383 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Cross6b76c152021-09-09 09:36:25 -0700384 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700385
Colin Cross08dca382020-07-21 20:31:17 -0700386 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700387
388 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000389 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700390 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700391 }
392 })
Colin Cross014489c2020-06-02 20:09:13 -0700393
Colin Cross31972dc2021-03-04 10:44:12 -0800394 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
395 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800396 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700397
Pedro Loureiro18233a22021-06-08 18:11:21 +0000398 var apiVersionsName, apiVersionsPrebuilt string
Pedro Loureiroffb643f2021-07-05 13:53:36 +0000399 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
400 // When compiling an SDK module (or system server) we use the filtered
401 // database because otherwise lint's
Pedro Loureiro18233a22021-06-08 18:11:21 +0000402 // NewApi check produces too many false positives; This database excludes information
403 // about classes created in mainline modules hence removing those false positives.
404 apiVersionsName = "api_versions_public_filtered.xml"
405 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
406 } else {
407 apiVersionsName = "api_versions.xml"
408 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
409 }
410
Colin Cross8a6ed372020-07-06 11:45:51 -0700411 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900412 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700413 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
Pedro Loureiro18233a22021-06-08 18:11:21 +0000414 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
Colin Cross8a6ed372020-07-06 11:45:51 -0700415 } else {
416 annotationsZipPath = copiedAnnotationsZipPath(ctx)
Pedro Loureiro18233a22021-06-08 18:11:21 +0000417 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700418 }
419
Colin Cross31972dc2021-03-04 10:44:12 -0800420 cmd := rule.Command()
421
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000422 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800423 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700424 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800425 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
426
Colin Cross1661aff2021-03-12 17:56:51 -0800427 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700428 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800429 FlagWithInput("--project ", lintPaths.projectXML).
430 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700431 FlagWithOutput("--html ", html).
432 FlagWithOutput("--text ", text).
433 FlagWithOutput("--xml ", xml).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000434 FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
Colin Cross014489c2020-06-02 20:09:13 -0700435 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
436 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
437 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
438 Flag("--exitcode").
Colin Cross62695b92022-08-12 16:09:24 -0700439 Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
Colin Cross014489c2020-06-02 20:09:13 -0700440 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800441 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700442 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700443
Colin Cross1661aff2021-03-12 17:56:51 -0800444 rule.Temporary(lintPaths.projectXML)
445 rule.Temporary(lintPaths.configXML)
446
Colin Cross988dfcc2020-07-16 17:32:17 -0700447 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
448 cmd.FlagWithArg("--check ", checkOnly)
449 }
450
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700451 lintBaseline := l.getBaselineFilepath(ctx)
452 if lintBaseline.Valid() {
453 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000454 }
455
Colin Cross6b76c152021-09-09 09:36:25 -0700456 cmd.FlagWithOutput("--write-reference-baseline ", baseline)
457
Colin Cross31972dc2021-03-04 10:44:12 -0800458 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700459
Colin Cross31972dc2021-03-04 10:44:12 -0800460 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700461
Colin Crossee4a8b72021-04-05 18:38:05 -0700462 // The HTML output contains a date, remove it to make the output deterministic.
463 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
464
Colin Cross62695b92022-08-12 16:09:24 -0700465 // The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
466 // export them out of the sandbox.
467 rule.Command().BuiltTool("soong_zip").
468 FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
469 FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
470 FlagWithInput("-r ", srcsList)
471
Colin Crossf1a035e2020-11-16 17:32:30 -0800472 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700473
Colin Crossc0efd1d2020-07-03 11:56:24 -0700474 l.outputs = lintOutputs{
475 html: html,
476 text: text,
477 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700478
Colin Cross08dca382020-07-21 20:31:17 -0700479 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700480 }
Colin Cross014489c2020-06-02 20:09:13 -0700481
Colin Crossc0efd1d2020-07-03 11:56:24 -0700482 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700483 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700484 }
485}
Colin Cross014489c2020-06-02 20:09:13 -0700486
Colin Cross08dca382020-07-21 20:31:17 -0700487func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
488 htmlList := depSets.HTML.ToSortedList()
489 textList := depSets.Text.ToSortedList()
490 xmlList := depSets.XML.ToSortedList()
491
492 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
493 return nil
494 }
495
496 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
497 lintZip(ctx, htmlList, htmlZip)
498
499 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
500 lintZip(ctx, textList, textZip)
501
502 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
503 lintZip(ctx, xmlList, xmlZip)
504
505 return android.Paths{htmlZip, textZip, xmlZip}
506}
507
Colin Cross014489c2020-06-02 20:09:13 -0700508type lintSingleton struct {
509 htmlZip android.WritablePath
510 textZip android.WritablePath
511 xmlZip android.WritablePath
512}
513
514func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
515 l.generateLintReportZips(ctx)
516 l.copyLintDependencies(ctx)
517}
518
Pedro Loureiro18233a22021-06-08 18:11:21 +0000519func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
520 var res android.Module
521 ctx.VisitAllModules(func(m android.Module) {
522 if ctx.ModuleName(m) == moduleName {
523 if res == nil {
524 res = m
525 } else {
526 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
527 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
528 }
529 }
530 })
531 return res
532}
533
Colin Cross014489c2020-06-02 20:09:13 -0700534func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900535 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700536 return
537 }
538
Anton Hansson67cf60e2022-05-09 09:36:22 +0000539 apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
540 if apiVersionsDb == nil {
Colin Cross014489c2020-06-02 20:09:13 -0700541 if !ctx.Config().AllowMissingDependencies() {
Anton Hansson67cf60e2022-05-09 09:36:22 +0000542 ctx.Errorf("lint: missing module api_versions_public")
Colin Cross014489c2020-06-02 20:09:13 -0700543 }
544 return
545 }
546
Anton Hanssonea17a452022-05-09 09:42:17 +0000547 sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
548 if sdkAnnotations == nil {
549 if !ctx.Config().AllowMissingDependencies() {
550 ctx.Errorf("lint: missing module sdk-annotations.zip")
551 }
552 return
553 }
554
Pedro Loureiro18233a22021-06-08 18:11:21 +0000555 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
556 if filteredDb == nil {
557 if !ctx.Config().AllowMissingDependencies() {
558 ctx.Errorf("lint: missing api-versions-xml-public-filtered")
559 }
560 return
561 }
562
Colin Cross014489c2020-06-02 20:09:13 -0700563 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800564 Rule: android.CpIfChanged,
Anton Hanssonea17a452022-05-09 09:42:17 +0000565 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
Colin Cross8a6ed372020-07-06 11:45:51 -0700566 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700567 })
568
569 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800570 Rule: android.CpIfChanged,
Anton Hansson67cf60e2022-05-09 09:36:22 +0000571 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
Pedro Loureiro18233a22021-06-08 18:11:21 +0000572 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
573 })
574
575 ctx.Build(pctx, android.BuildParams{
576 Rule: android.CpIfChanged,
577 Input: android.OutputFileForModule(ctx, filteredDb, ""),
578 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
Colin Cross014489c2020-06-02 20:09:13 -0700579 })
580}
581
Colin Cross8a6ed372020-07-06 11:45:51 -0700582func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700583 return android.PathForOutput(ctx, "lint", "annotations.zip")
584}
585
Pedro Loureiro18233a22021-06-08 18:11:21 +0000586func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
587 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700588}
589
590func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700591 if ctx.Config().UnbundledBuild() {
592 return
593 }
594
Colin Cross014489c2020-06-02 20:09:13 -0700595 var outputs []*lintOutputs
596 var dirs []string
597 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500598 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700599 return
600 }
601
Colin Cross56a83212020-09-15 18:30:11 -0700602 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
603 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
604 if apexInfo.IsForPlatform() {
605 // There are stray platform variants of modules in apexes that are not available for
606 // the platform, and they sometimes can't be built. Don't depend on them.
607 return
608 }
Colin Cross014489c2020-06-02 20:09:13 -0700609 }
610
Colin Cross08dca382020-07-21 20:31:17 -0700611 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700612 outputs = append(outputs, l.lintOutputs())
613 }
614 })
615
616 dirs = android.SortedUniqueStrings(dirs)
617
618 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
619 var paths android.Paths
620
621 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700622 if p := get(output); p != nil {
623 paths = append(paths, p)
624 }
Colin Cross014489c2020-06-02 20:09:13 -0700625 }
626
Colin Crossc0efd1d2020-07-03 11:56:24 -0700627 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700628 }
629
630 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
631 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
632
633 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
634 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
635
636 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
637 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
638
639 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
640}
641
642func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700643 if !ctx.Config().UnbundledBuild() {
644 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
645 }
Colin Cross014489c2020-06-02 20:09:13 -0700646}
647
648var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
649
650func init() {
651 android.RegisterSingletonType("lint",
652 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700653
654 registerLintBuildComponents(android.InitRegistrationContext)
655}
656
657func registerLintBuildComponents(ctx android.RegistrationContext) {
658 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
659 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
660 })
Colin Cross014489c2020-06-02 20:09:13 -0700661}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700662
663func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
664 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
665
666 sort.Slice(paths, func(i, j int) bool {
667 return paths[i].String() < paths[j].String()
668 })
669
Colin Crossf1a035e2020-11-16 17:32:30 -0800670 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700671
Colin Crossf1a035e2020-11-16 17:32:30 -0800672 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700673 FlagWithOutput("-o ", outputPath).
674 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800675 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700676
Colin Crossf1a035e2020-11-16 17:32:30 -0800677 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700678}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700679
680// Enforce the strict updatability linting to all applicable transitive dependencies.
681func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
682 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000683 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700684 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000685 if a, ok := d.(LintDepSetsIntf); ok {
686 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700687 }
688 })
689 }
690}