blob: f09db955d181ff7b4ba06ebfa220d617438a82f1 [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 Cross31972dc2021-03-04 10:44:12 -0800213func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) 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.
244 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
245 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
Colin Cross014489c2020-06-02 20:09:13 -0700246
247 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700248
Colin Cross5bedfa22021-03-23 17:07:14 -0700249 if len(l.resources) > 0 {
250 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
251 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700252 }
253
254 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700255 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700256 }
257
Colin Cross5bedfa22021-03-23 17:07:14 -0700258 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700259
Colin Cross5bedfa22021-03-23 17:07:14 -0700260 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700261
Colin Cross1661aff2021-03-12 17:56:51 -0800262 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700263
264 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
265 // the root dir is not set.
266 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700267
268 cmd.FlagWithInput("@",
269 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
270
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000271 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700272 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
273 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
274 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
275 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
276
Spandan Das17854f52022-01-14 21:19:14 +0000277 if l.GetStrictUpdatabilityLinting() {
Jaewoong Jung3c87b1d2021-04-22 11:01:36 -0700278 // Verify the module does not baseline issues that endanger safe updatability.
Jaewoong Jung48de8832021-04-21 16:17:25 -0700279 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
280 cmd.FlagWithInput("--baseline ", baselinePath.Path())
281 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
282 }
283 }
284
Colin Cross31972dc2021-03-04 10:44:12 -0800285 return lintPaths{
286 projectXML: projectXMLPath,
287 configXML: configXMLPath,
288 cacheDir: cacheDir,
289 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800290 }
291
Colin Cross014489c2020-06-02 20:09:13 -0700292}
293
Liz Kammer20ebfb42020-07-28 11:32:07 -0700294// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700295// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800296func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700297 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
298
299 rule.Command().Text("(").
300 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
301 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
302 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000303 Textf(`echo " <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
304 l.minSdkVersion, l.targetSdkVersion).
Colin Cross014489c2020-06-02 20:09:13 -0700305 Text(`echo "</manifest>"`).
306 Text(") >").Output(manifestPath)
307
308 return manifestPath
309}
310
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700311func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
312 var lintBaseline android.OptionalPath
313 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
314 if String(l.properties.Lint.Baseline_filename) != "" {
315 // if manually specified, we require the file to exist
316 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
317 } else {
318 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
319 }
320 }
321 return lintBaseline
322}
323
Colin Cross014489c2020-06-02 20:09:13 -0700324func (l *linter) lint(ctx android.ModuleContext) {
325 if !l.enabled() {
326 return
327 }
328
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000329 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700330 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
331 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
332 if len(filtered) != 0 {
333 ctx.PropertyErrorf("lint.warning_checks",
334 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
335 }
336 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
337 if len(filtered) != 0 {
338 ctx.PropertyErrorf("lint.disabled_checks",
339 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
340 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000341 }
342
Colin Cross92e4b462020-06-18 15:56:48 -0700343 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
344 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800345 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
346 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
347 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700348 } else {
349 ctx.PropertyErrorf("lint.extra_check_modules",
350 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
351 }
352 }
353
Colin Cross1661aff2021-03-12 17:56:51 -0800354 rule := android.NewRuleBuilder(pctx, ctx).
355 Sbox(android.PathForModuleOut(ctx, "lint"),
356 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
357 SandboxInputs()
358
359 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
360 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
361 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
362 rule.Rewrapper(&remoteexec.REParams{
363 Labels: map[string]string{"type": "tool", "name": "lint"},
364 ExecStrategy: lintRBEExecStrategy(ctx),
365 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700366 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800367 })
368 }
Colin Cross014489c2020-06-02 20:09:13 -0700369
370 if l.manifest == nil {
371 manifest := l.generateManifest(ctx, rule)
372 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800373 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700374 }
375
Colin Cross31972dc2021-03-04 10:44:12 -0800376 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700377
Colin Cross1661aff2021-03-12 17:56:51 -0800378 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
379 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
380 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Cross6b76c152021-09-09 09:36:25 -0700381 baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700382
Colin Cross08dca382020-07-21 20:31:17 -0700383 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700384
385 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000386 if depLint, ok := dep.(LintDepSetsIntf); ok {
Colin Cross08dca382020-07-21 20:31:17 -0700387 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700388 }
389 })
Colin Cross014489c2020-06-02 20:09:13 -0700390
Colin Cross31972dc2021-03-04 10:44:12 -0800391 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
392 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800393 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700394
Pedro Loureiro18233a22021-06-08 18:11:21 +0000395 var apiVersionsName, apiVersionsPrebuilt string
Pedro Loureiroffb643f2021-07-05 13:53:36 +0000396 if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
397 // When compiling an SDK module (or system server) we use the filtered
398 // database because otherwise lint's
Pedro Loureiro18233a22021-06-08 18:11:21 +0000399 // NewApi check produces too many false positives; This database excludes information
400 // about classes created in mainline modules hence removing those false positives.
401 apiVersionsName = "api_versions_public_filtered.xml"
402 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
403 } else {
404 apiVersionsName = "api_versions.xml"
405 apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
406 }
407
Colin Cross8a6ed372020-07-06 11:45:51 -0700408 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900409 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700410 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
Pedro Loureiro18233a22021-06-08 18:11:21 +0000411 apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
Colin Cross8a6ed372020-07-06 11:45:51 -0700412 } else {
413 annotationsZipPath = copiedAnnotationsZipPath(ctx)
Pedro Loureiro18233a22021-06-08 18:11:21 +0000414 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
Colin Cross8a6ed372020-07-06 11:45:51 -0700415 }
416
Colin Cross31972dc2021-03-04 10:44:12 -0800417 cmd := rule.Command()
418
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000419 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800420 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700421 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800422 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
423
Colin Cross1661aff2021-03-12 17:56:51 -0800424 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700425 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800426 FlagWithInput("--project ", lintPaths.projectXML).
427 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700428 FlagWithOutput("--html ", html).
429 FlagWithOutput("--text ", text).
430 FlagWithOutput("--xml ", xml).
Cole Fauste5bf3fb2022-07-01 19:39:14 +0000431 FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
Colin Cross014489c2020-06-02 20:09:13 -0700432 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
433 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
434 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
435 Flag("--exitcode").
436 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800437 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700438 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700439
Colin Cross1661aff2021-03-12 17:56:51 -0800440 rule.Temporary(lintPaths.projectXML)
441 rule.Temporary(lintPaths.configXML)
442
Colin Cross988dfcc2020-07-16 17:32:17 -0700443 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
444 cmd.FlagWithArg("--check ", checkOnly)
445 }
446
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700447 lintBaseline := l.getBaselineFilepath(ctx)
448 if lintBaseline.Valid() {
449 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000450 }
451
Colin Cross6b76c152021-09-09 09:36:25 -0700452 cmd.FlagWithOutput("--write-reference-baseline ", baseline)
453
Colin Cross31972dc2021-03-04 10:44:12 -0800454 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700455
Colin Cross31972dc2021-03-04 10:44:12 -0800456 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700457
Colin Crossee4a8b72021-04-05 18:38:05 -0700458 // The HTML output contains a date, remove it to make the output deterministic.
459 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
460
Colin Crossf1a035e2020-11-16 17:32:30 -0800461 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700462
Colin Crossc0efd1d2020-07-03 11:56:24 -0700463 l.outputs = lintOutputs{
464 html: html,
465 text: text,
466 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700467
Colin Cross08dca382020-07-21 20:31:17 -0700468 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700469 }
Colin Cross014489c2020-06-02 20:09:13 -0700470
Colin Crossc0efd1d2020-07-03 11:56:24 -0700471 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700472 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700473 }
474}
Colin Cross014489c2020-06-02 20:09:13 -0700475
Colin Cross08dca382020-07-21 20:31:17 -0700476func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
477 htmlList := depSets.HTML.ToSortedList()
478 textList := depSets.Text.ToSortedList()
479 xmlList := depSets.XML.ToSortedList()
480
481 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
482 return nil
483 }
484
485 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
486 lintZip(ctx, htmlList, htmlZip)
487
488 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
489 lintZip(ctx, textList, textZip)
490
491 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
492 lintZip(ctx, xmlList, xmlZip)
493
494 return android.Paths{htmlZip, textZip, xmlZip}
495}
496
Colin Cross014489c2020-06-02 20:09:13 -0700497type lintSingleton struct {
498 htmlZip android.WritablePath
499 textZip android.WritablePath
500 xmlZip android.WritablePath
501}
502
503func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
504 l.generateLintReportZips(ctx)
505 l.copyLintDependencies(ctx)
506}
507
Pedro Loureiro18233a22021-06-08 18:11:21 +0000508func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
509 var res android.Module
510 ctx.VisitAllModules(func(m android.Module) {
511 if ctx.ModuleName(m) == moduleName {
512 if res == nil {
513 res = m
514 } else {
515 ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
516 ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
517 }
518 }
519 })
520 return res
521}
522
Colin Cross014489c2020-06-02 20:09:13 -0700523func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900524 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700525 return
526 }
527
Pedro Loureiro18233a22021-06-08 18:11:21 +0000528 frameworkDocStubs := findModuleOrErr(ctx, "framework-doc-stubs")
Colin Cross014489c2020-06-02 20:09:13 -0700529 if frameworkDocStubs == nil {
530 if !ctx.Config().AllowMissingDependencies() {
531 ctx.Errorf("lint: missing framework-doc-stubs")
532 }
533 return
534 }
535
Pedro Loureiro18233a22021-06-08 18:11:21 +0000536 filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
537 if filteredDb == nil {
538 if !ctx.Config().AllowMissingDependencies() {
539 ctx.Errorf("lint: missing api-versions-xml-public-filtered")
540 }
541 return
542 }
543
Colin Cross014489c2020-06-02 20:09:13 -0700544 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800545 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700546 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700547 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700548 })
549
550 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800551 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700552 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Pedro Loureiro18233a22021-06-08 18:11:21 +0000553 Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
554 })
555
556 ctx.Build(pctx, android.BuildParams{
557 Rule: android.CpIfChanged,
558 Input: android.OutputFileForModule(ctx, filteredDb, ""),
559 Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
Colin Cross014489c2020-06-02 20:09:13 -0700560 })
561}
562
Colin Cross8a6ed372020-07-06 11:45:51 -0700563func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700564 return android.PathForOutput(ctx, "lint", "annotations.zip")
565}
566
Pedro Loureiro18233a22021-06-08 18:11:21 +0000567func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
568 return android.PathForOutput(ctx, "lint", name)
Colin Cross014489c2020-06-02 20:09:13 -0700569}
570
571func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700572 if ctx.Config().UnbundledBuild() {
573 return
574 }
575
Colin Cross014489c2020-06-02 20:09:13 -0700576 var outputs []*lintOutputs
577 var dirs []string
578 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500579 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700580 return
581 }
582
Colin Cross56a83212020-09-15 18:30:11 -0700583 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
584 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
585 if apexInfo.IsForPlatform() {
586 // There are stray platform variants of modules in apexes that are not available for
587 // the platform, and they sometimes can't be built. Don't depend on them.
588 return
589 }
Colin Cross014489c2020-06-02 20:09:13 -0700590 }
591
Colin Cross08dca382020-07-21 20:31:17 -0700592 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700593 outputs = append(outputs, l.lintOutputs())
594 }
595 })
596
597 dirs = android.SortedUniqueStrings(dirs)
598
599 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
600 var paths android.Paths
601
602 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700603 if p := get(output); p != nil {
604 paths = append(paths, p)
605 }
Colin Cross014489c2020-06-02 20:09:13 -0700606 }
607
Colin Crossc0efd1d2020-07-03 11:56:24 -0700608 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700609 }
610
611 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
612 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
613
614 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
615 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
616
617 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
618 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
619
620 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
621}
622
623func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700624 if !ctx.Config().UnbundledBuild() {
625 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
626 }
Colin Cross014489c2020-06-02 20:09:13 -0700627}
628
629var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
630
631func init() {
632 android.RegisterSingletonType("lint",
633 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700634
635 registerLintBuildComponents(android.InitRegistrationContext)
636}
637
638func registerLintBuildComponents(ctx android.RegistrationContext) {
639 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
640 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
641 })
Colin Cross014489c2020-06-02 20:09:13 -0700642}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700643
644func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
645 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
646
647 sort.Slice(paths, func(i, j int) bool {
648 return paths[i].String() < paths[j].String()
649 })
650
Colin Crossf1a035e2020-11-16 17:32:30 -0800651 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700652
Colin Crossf1a035e2020-11-16 17:32:30 -0800653 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700654 FlagWithOutput("-o ", outputPath).
655 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800656 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700657
Colin Crossf1a035e2020-11-16 17:32:30 -0800658 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700659}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700660
661// Enforce the strict updatability linting to all applicable transitive dependencies.
662func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
663 m := ctx.Module()
Spandan Das17854f52022-01-14 21:19:14 +0000664 if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() {
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700665 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
Spandan Das17854f52022-01-14 21:19:14 +0000666 if a, ok := d.(LintDepSetsIntf); ok {
667 a.SetStrictUpdatabilityLinting(true)
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700668 }
669 })
670 }
671}