blob: 22c9ec49f37679832d3b3df73c1c103f3a4ef32c [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
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000022 "github.com/google/blueprint/proptools"
23
Colin Cross014489c2020-06-02 20:09:13 -070024 "android/soong/android"
Colin Cross31972dc2021-03-04 10:44:12 -080025 "android/soong/java/config"
26 "android/soong/remoteexec"
Colin Cross014489c2020-06-02 20:09:13 -070027)
28
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -070029// lint checks automatically enforced for modules that have different min_sdk_version than
30// sdk_version
31var updatabilityChecks = []string{"NewApi"}
32
Colin Cross014489c2020-06-02 20:09:13 -070033type LintProperties struct {
34 // Controls for running Android Lint on the module.
35 Lint struct {
36
37 // If true, run Android Lint on the module. Defaults to true.
38 Enabled *bool
39
40 // Flags to pass to the Android Lint tool.
41 Flags []string
42
43 // Checks that should be treated as fatal.
44 Fatal_checks []string
45
46 // Checks that should be treated as errors.
47 Error_checks []string
48
49 // Checks that should be treated as warnings.
50 Warning_checks []string
51
52 // Checks that should be skipped.
53 Disabled_checks []string
Colin Cross92e4b462020-06-18 15:56:48 -070054
55 // Modules that provide extra lint checks
56 Extra_check_modules []string
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000057
58 // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
59 Baseline_filename *string
Jaewoong Jung48de8832021-04-21 16:17:25 -070060
61 // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
62 Strict_updatability_linting *bool
Colin Cross014489c2020-06-02 20:09:13 -070063 }
64}
65
66type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000067 name string
68 manifest android.Path
69 mergedManifest android.Path
70 srcs android.Paths
71 srcJars android.Paths
72 resources android.Paths
73 classpath android.Paths
74 classes android.Path
75 extraLintCheckJars android.Paths
76 test bool
77 library bool
Nataniel Borges5d80d892022-04-29 09:49:16 +000078 minSdkVersion android.ApiLevel
79 targetSdkVersion android.ApiLevel
80 compileSdkVersion android.ApiLevel
Pedro Loureiro18233a22021-06-08 18:11:21 +000081 compileSdkKind android.SdkKind
Pedro Loureirof4a88b12021-02-25 16:23:22 +000082 javaLanguageLevel string
83 kotlinLanguageLevel string
84 outputs lintOutputs
85 properties LintProperties
86 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070087
Colin Cross08dca382020-07-21 20:31:17 -070088 reports android.Paths
89
Colin Crossc0efd1d2020-07-03 11:56:24 -070090 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070091}
92
93type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070094 html android.Path
95 text android.Path
96 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070097
Colin Cross08dca382020-07-21 20:31:17 -070098 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -070099}
100
Colin Cross08dca382020-07-21 20:31:17 -0700101type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -0700102 lintOutputs() *lintOutputs
103}
104
Spandan Das17854f52022-01-14 21:19:14 +0000105type LintDepSetsIntf interface {
Colin Cross08dca382020-07-21 20:31:17 -0700106 LintDepSets() LintDepSets
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700107
108 // Methods used to propagate strict_updatability_linting values.
Spandan Das17854f52022-01-14 21:19:14 +0000109 GetStrictUpdatabilityLinting() bool
110 SetStrictUpdatabilityLinting(bool)
Colin Cross08dca382020-07-21 20:31:17 -0700111}
112
113type LintDepSets struct {
114 HTML, Text, XML *android.DepSet
115}
116
117type LintDepSetsBuilder struct {
118 HTML, Text, XML *android.DepSetBuilder
119}
120
121func NewLintDepSetBuilder() LintDepSetsBuilder {
122 return LintDepSetsBuilder{
123 HTML: android.NewDepSetBuilder(android.POSTORDER),
124 Text: android.NewDepSetBuilder(android.POSTORDER),
125 XML: android.NewDepSetBuilder(android.POSTORDER),
126 }
127}
128
129func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
130 l.HTML.Direct(html)
131 l.Text.Direct(text)
132 l.XML.Direct(xml)
133 return l
134}
135
136func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
137 if depSets.HTML != nil {
138 l.HTML.Transitive(depSets.HTML)
139 }
140 if depSets.Text != nil {
141 l.Text.Transitive(depSets.Text)
142 }
143 if depSets.XML != nil {
144 l.XML.Transitive(depSets.XML)
145 }
146 return l
147}
148
149func (l LintDepSetsBuilder) Build() LintDepSets {
150 return LintDepSets{
151 HTML: l.HTML.Build(),
152 Text: l.Text.Build(),
153 XML: l.XML.Build(),
154 }
155}
156
157func (l *linter) LintDepSets() LintDepSets {
158 return l.outputs.depSets
159}
160
Spandan Das17854f52022-01-14 21:19:14 +0000161func (l *linter) GetStrictUpdatabilityLinting() bool {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700162 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
163}
164
Spandan Das17854f52022-01-14 21:19:14 +0000165func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700166 l.properties.Lint.Strict_updatability_linting = &strictLinting
167}
168
Spandan Das17854f52022-01-14 21:19:14 +0000169var _ LintDepSetsIntf = (*linter)(nil)
Colin Cross08dca382020-07-21 20:31:17 -0700170
171var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700172
173func (l *linter) lintOutputs() *lintOutputs {
174 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700175}
176
177func (l *linter) enabled() bool {
178 return BoolDefault(l.properties.Lint.Enabled, true)
179}
180
Colin Cross92e4b462020-06-18 15:56:48 -0700181func (l *linter) deps(ctx android.BottomUpMutatorContext) {
182 if !l.enabled() {
183 return
184 }
185
Colin Cross988dfcc2020-07-16 17:32:17 -0700186 extraCheckModules := l.properties.Lint.Extra_check_modules
187
188 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
189 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
190 extraCheckModules = strings.Split(checkOnlyModules, ",")
191 }
192 }
193
194 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
195 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700196}
197
Colin Crossad22bc22021-03-10 09:45:40 -0800198// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
199// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800200type lintPaths struct {
201 projectXML android.WritablePath
202 configXML android.WritablePath
203 cacheDir android.WritablePath
204 homeDir android.WritablePath
205 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800206}
207
Colin Cross9b93af42021-03-10 10:40:58 -0800208func lintRBEExecStrategy(ctx android.ModuleContext) string {
209 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
210}
211
Colin Cross31972dc2021-03-04 10:44:12 -0800212func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800213 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700214 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800215 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
216 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
217 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700218
Colin Cross1661aff2021-03-12 17:56:51 -0800219 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700220 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
221
222 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700223 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700224 FlagWithOutput("--project_out ", projectXMLPath).
225 FlagWithOutput("--config_out ", configXMLPath).
226 FlagWithArg("--name ", ctx.ModuleName())
227
228 if l.library {
229 cmd.Flag("--library")
230 }
231 if l.test {
232 cmd.Flag("--test")
233 }
234 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700235 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700236 }
237 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700238 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700239 }
240
Colin Cross5bedfa22021-03-23 17:07:14 -0700241 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
242 // lint separately.
243 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
244 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
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' >" &&`).
Nataniel Borges5d80d892022-04-29 09:49:16 +0000302 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
303 l.minSdkVersion.String(), l.targetSdkVersion.String()).
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
Nataniel Borges5d80d892022-04-29 09:49:16 +0000328 if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
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 Cross31972dc2021-03-04 10:44:12 -0800375 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700376
Colin Cross1661aff2021-03-12 17:56:51 -0800377 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
378 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
379 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Cross6b76c152021-09-09 09:36:25 -0700380 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700381
Colin Cross08dca382020-07-21 20:31:17 -0700382 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700383
384 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000385 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700386 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700387 }
388 })
Colin Cross014489c2020-06-02 20:09:13 -0700389
Colin Cross31972dc2021-03-04 10:44:12 -0800390 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
391 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800392 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700393
Pedro Loureiro18233a22021-06-08 18:11:21 +0000394 var apiVersionsName, apiVersionsPrebuilt string
Pedro Loureiroffb643f2021-07-05 13:53:36 +0000395 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
396 // When compiling an SDK module (or system server) we use the filtered
397 // database because otherwise lint's
Pedro Loureiro18233a22021-06-08 18:11:21 +0000398 // NewApi check produces too many false positives; This database excludes information
399 // about classes created in mainline modules hence removing those false positives.
400 apiVersionsName = "api_versions_public_filtered.xml"
401 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
402 } else {
403 apiVersionsName = "api_versions.xml"
404 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
405 }
406
Colin Cross8a6ed372020-07-06 11:45:51 -0700407 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900408 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700409 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
Pedro Loureiro18233a22021-06-08 18:11:21 +0000410 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
Colin Cross8a6ed372020-07-06 11:45:51 -0700411 } else {
412 annotationsZipPath = copiedAnnotationsZipPath(ctx)
Pedro Loureiro18233a22021-06-08 18:11:21 +0000413 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700414 }
415
Colin Cross31972dc2021-03-04 10:44:12 -0800416 cmd := rule.Command()
417
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000418 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800419 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700420 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800421 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
422
Colin Cross1661aff2021-03-12 17:56:51 -0800423 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700424 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800425 FlagWithInput("--project ", lintPaths.projectXML).
426 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700427 FlagWithOutput("--html ", html).
428 FlagWithOutput("--text ", text).
429 FlagWithOutput("--xml ", xml).
Nataniel Borges5d80d892022-04-29 09:49:16 +0000430 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
Colin Cross014489c2020-06-02 20:09:13 -0700431 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
432 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
433 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
434 Flag("--exitcode").
435 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800436 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700437 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700438
Colin Cross1661aff2021-03-12 17:56:51 -0800439 rule.Temporary(lintPaths.projectXML)
440 rule.Temporary(lintPaths.configXML)
441
Colin Cross988dfcc2020-07-16 17:32:17 -0700442 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
443 cmd.FlagWithArg("--check ", checkOnly)
444 }
445
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700446 lintBaseline := l.getBaselineFilepath(ctx)
447 if lintBaseline.Valid() {
448 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000449 }
450
Colin Cross6b76c152021-09-09 09:36:25 -0700451 cmd.FlagWithOutput("--write-reference-baseline ", baseline)
452
Colin Cross31972dc2021-03-04 10:44:12 -0800453 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700454
Colin Cross31972dc2021-03-04 10:44:12 -0800455 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700456
Colin Crossee4a8b72021-04-05 18:38:05 -0700457 // The HTML output contains a date, remove it to make the output deterministic.
458 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
459
Colin Crossf1a035e2020-11-16 17:32:30 -0800460 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700461
Colin Crossc0efd1d2020-07-03 11:56:24 -0700462 l.outputs = lintOutputs{
463 html: html,
464 text: text,
465 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700466
Colin Cross08dca382020-07-21 20:31:17 -0700467 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700468 }
Colin Cross014489c2020-06-02 20:09:13 -0700469
Colin Crossc0efd1d2020-07-03 11:56:24 -0700470 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700471 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700472 }
473}
Colin Cross014489c2020-06-02 20:09:13 -0700474
Colin Cross08dca382020-07-21 20:31:17 -0700475func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
476 htmlList := depSets.HTML.ToSortedList()
477 textList := depSets.Text.ToSortedList()
478 xmlList := depSets.XML.ToSortedList()
479
480 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
481 return nil
482 }
483
484 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
485 lintZip(ctx, htmlList, htmlZip)
486
487 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
488 lintZip(ctx, textList, textZip)
489
490 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
491 lintZip(ctx, xmlList, xmlZip)
492
493 return android.Paths{htmlZip, textZip, xmlZip}
494}
495
Colin Cross014489c2020-06-02 20:09:13 -0700496type lintSingleton struct {
497 htmlZip android.WritablePath
498 textZip android.WritablePath
499 xmlZip android.WritablePath
500}
501
502func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
503 l.generateLintReportZips(ctx)
504 l.copyLintDependencies(ctx)
505}
506
Pedro Loureiro18233a22021-06-08 18:11:21 +0000507func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
508 var res android.Module
509 ctx.VisitAllModules(func(m android.Module) {
510 if ctx.ModuleName(m) == moduleName {
511 if res == nil {
512 res = m
513 } else {
514 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
515 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
516 }
517 }
518 })
519 return res
520}
521
Colin Cross014489c2020-06-02 20:09:13 -0700522func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900523 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700524 return
525 }
526
Anton Hansson67cf60e2022-05-09 09:36:22 +0000527 apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
528 if apiVersionsDb == nil {
Colin Cross014489c2020-06-02 20:09:13 -0700529 if !ctx.Config().AllowMissingDependencies() {
Anton Hansson67cf60e2022-05-09 09:36:22 +0000530 ctx.Errorf("lint: missing module api_versions_public")
Colin Cross014489c2020-06-02 20:09:13 -0700531 }
532 return
533 }
534
Anton Hanssonea17a452022-05-09 09:42:17 +0000535 sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
536 if sdkAnnotations == nil {
537 if !ctx.Config().AllowMissingDependencies() {
538 ctx.Errorf("lint: missing module sdk-annotations.zip")
539 }
540 return
541 }
542
Pedro Loureiro18233a22021-06-08 18:11:21 +0000543 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
544 if filteredDb == nil {
545 if !ctx.Config().AllowMissingDependencies() {
546 ctx.Errorf("lint: missing api-versions-xml-public-filtered")
547 }
548 return
549 }
550
Colin Cross014489c2020-06-02 20:09:13 -0700551 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800552 Rule: android.CpIfChanged,
Anton Hanssonea17a452022-05-09 09:42:17 +0000553 Input: android.OutputFileForModule(ctx, sdkAnnotations, ""),
Colin Cross8a6ed372020-07-06 11:45:51 -0700554 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700555 })
556
557 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800558 Rule: android.CpIfChanged,
Anton Hansson67cf60e2022-05-09 09:36:22 +0000559 Input: android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
Pedro Loureiro18233a22021-06-08 18:11:21 +0000560 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
561 })
562
563 ctx.Build(pctx, android.BuildParams{
564 Rule: android.CpIfChanged,
565 Input: android.OutputFileForModule(ctx, filteredDb, ""),
566 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
Colin Cross014489c2020-06-02 20:09:13 -0700567 })
568}
569
Colin Cross8a6ed372020-07-06 11:45:51 -0700570func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700571 return android.PathForOutput(ctx, "lint", "annotations.zip")
572}
573
Pedro Loureiro18233a22021-06-08 18:11:21 +0000574func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
575 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700576}
577
578func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700579 if ctx.Config().UnbundledBuild() {
580 return
581 }
582
Colin Cross014489c2020-06-02 20:09:13 -0700583 var outputs []*lintOutputs
584 var dirs []string
585 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500586 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700587 return
588 }
589
Colin Cross56a83212020-09-15 18:30:11 -0700590 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
591 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
592 if apexInfo.IsForPlatform() {
593 // There are stray platform variants of modules in apexes that are not available for
594 // the platform, and they sometimes can't be built. Don't depend on them.
595 return
596 }
Colin Cross014489c2020-06-02 20:09:13 -0700597 }
598
Colin Cross08dca382020-07-21 20:31:17 -0700599 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700600 outputs = append(outputs, l.lintOutputs())
601 }
602 })
603
604 dirs = android.SortedUniqueStrings(dirs)
605
606 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
607 var paths android.Paths
608
609 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700610 if p := get(output); p != nil {
611 paths = append(paths, p)
612 }
Colin Cross014489c2020-06-02 20:09:13 -0700613 }
614
Colin Crossc0efd1d2020-07-03 11:56:24 -0700615 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700616 }
617
618 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
619 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
620
621 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
622 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
623
624 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
625 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
626
627 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
628}
629
630func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700631 if !ctx.Config().UnbundledBuild() {
632 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
633 }
Colin Cross014489c2020-06-02 20:09:13 -0700634}
635
636var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
637
638func init() {
639 android.RegisterSingletonType("lint",
640 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700641
642 registerLintBuildComponents(android.InitRegistrationContext)
643}
644
645func registerLintBuildComponents(ctx android.RegistrationContext) {
646 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
647 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
648 })
Colin Cross014489c2020-06-02 20:09:13 -0700649}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700650
651func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
652 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
653
654 sort.Slice(paths, func(i, j int) bool {
655 return paths[i].String() < paths[j].String()
656 })
657
Colin Crossf1a035e2020-11-16 17:32:30 -0800658 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700659
Colin Crossf1a035e2020-11-16 17:32:30 -0800660 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700661 FlagWithOutput("-o ", outputPath).
662 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800663 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700664
Colin Crossf1a035e2020-11-16 17:32:30 -0800665 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700666}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700667
668// Enforce the strict updatability linting to all applicable transitive dependencies.
669func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
670 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000671 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700672 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000673 if a, ok := d.(LintDepSetsIntf); ok {
674 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700675 }
676 })
677 }
678}