blob: 1511cfe268bea7070dede228a37bdd20215b4804 [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
78 minSdkVersion string
79 targetSdkVersion string
80 compileSdkVersion string
81 javaLanguageLevel string
82 kotlinLanguageLevel string
83 outputs lintOutputs
84 properties LintProperties
85 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070086
Colin Cross08dca382020-07-21 20:31:17 -070087 reports android.Paths
88
Colin Crossc0efd1d2020-07-03 11:56:24 -070089 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070090}
91
92type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070093 html android.Path
94 text android.Path
95 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070096
Colin Cross08dca382020-07-21 20:31:17 -070097 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -070098}
99
Colin Cross08dca382020-07-21 20:31:17 -0700100type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -0700101 lintOutputs() *lintOutputs
102}
103
Colin Cross08dca382020-07-21 20:31:17 -0700104type lintDepSetsIntf interface {
105 LintDepSets() LintDepSets
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700106
107 // Methods used to propagate strict_updatability_linting values.
108 getStrictUpdatabilityLinting() bool
109 setStrictUpdatabilityLinting(bool)
Colin Cross08dca382020-07-21 20:31:17 -0700110}
111
112type LintDepSets struct {
113 HTML, Text, XML *android.DepSet
114}
115
116type LintDepSetsBuilder struct {
117 HTML, Text, XML *android.DepSetBuilder
118}
119
120func NewLintDepSetBuilder() LintDepSetsBuilder {
121 return LintDepSetsBuilder{
122 HTML: android.NewDepSetBuilder(android.POSTORDER),
123 Text: android.NewDepSetBuilder(android.POSTORDER),
124 XML: android.NewDepSetBuilder(android.POSTORDER),
125 }
126}
127
128func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
129 l.HTML.Direct(html)
130 l.Text.Direct(text)
131 l.XML.Direct(xml)
132 return l
133}
134
135func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
136 if depSets.HTML != nil {
137 l.HTML.Transitive(depSets.HTML)
138 }
139 if depSets.Text != nil {
140 l.Text.Transitive(depSets.Text)
141 }
142 if depSets.XML != nil {
143 l.XML.Transitive(depSets.XML)
144 }
145 return l
146}
147
148func (l LintDepSetsBuilder) Build() LintDepSets {
149 return LintDepSets{
150 HTML: l.HTML.Build(),
151 Text: l.Text.Build(),
152 XML: l.XML.Build(),
153 }
154}
155
156func (l *linter) LintDepSets() LintDepSets {
157 return l.outputs.depSets
158}
159
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700160func (l *linter) getStrictUpdatabilityLinting() bool {
161 return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
162}
163
164func (l *linter) setStrictUpdatabilityLinting(strictLinting bool) {
165 l.properties.Lint.Strict_updatability_linting = &strictLinting
166}
167
Colin Cross08dca382020-07-21 20:31:17 -0700168var _ lintDepSetsIntf = (*linter)(nil)
169
170var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700171
172func (l *linter) lintOutputs() *lintOutputs {
173 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700174}
175
176func (l *linter) enabled() bool {
177 return BoolDefault(l.properties.Lint.Enabled, true)
178}
179
Colin Cross92e4b462020-06-18 15:56:48 -0700180func (l *linter) deps(ctx android.BottomUpMutatorContext) {
181 if !l.enabled() {
182 return
183 }
184
Colin Cross988dfcc2020-07-16 17:32:17 -0700185 extraCheckModules := l.properties.Lint.Extra_check_modules
186
187 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
188 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
189 extraCheckModules = strings.Split(checkOnlyModules, ",")
190 }
191 }
192
193 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
194 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700195}
196
Colin Crossad22bc22021-03-10 09:45:40 -0800197// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
198// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800199type lintPaths struct {
200 projectXML android.WritablePath
201 configXML android.WritablePath
202 cacheDir android.WritablePath
203 homeDir android.WritablePath
204 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800205}
206
Colin Cross9b93af42021-03-10 10:40:58 -0800207func lintRBEExecStrategy(ctx android.ModuleContext) string {
208 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
209}
210
Colin Cross31972dc2021-03-04 10:44:12 -0800211func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800212 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700213 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800214 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
215 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
216 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700217
Colin Cross1661aff2021-03-12 17:56:51 -0800218 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700219 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
220
221 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700222 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700223 FlagWithOutput("--project_out ", projectXMLPath).
224 FlagWithOutput("--config_out ", configXMLPath).
225 FlagWithArg("--name ", ctx.ModuleName())
226
227 if l.library {
228 cmd.Flag("--library")
229 }
230 if l.test {
231 cmd.Flag("--test")
232 }
233 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700234 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700235 }
236 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700237 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700238 }
239
Colin Cross5bedfa22021-03-23 17:07:14 -0700240 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
241 // lint separately.
242 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
243 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
Colin Cross014489c2020-06-02 20:09:13 -0700244
245 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700246
Colin Cross5bedfa22021-03-23 17:07:14 -0700247 if len(l.resources) > 0 {
248 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
249 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700250 }
251
252 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700253 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700254 }
255
Colin Cross5bedfa22021-03-23 17:07:14 -0700256 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700257
Colin Cross5bedfa22021-03-23 17:07:14 -0700258 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700259
Colin Cross1661aff2021-03-12 17:56:51 -0800260 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700261
262 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
263 // the root dir is not set.
264 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700265
266 cmd.FlagWithInput("@",
267 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
268
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000269 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700270 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
271 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
272 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
273 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
274
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700275 if l.getStrictUpdatabilityLinting() {
Jaewoong Jung3c87b1d2021-04-22 11:01:36 -0700276 // Verify the module does not baseline issues that endanger safe updatability.
Jaewoong Jung48de8832021-04-21 16:17:25 -0700277 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
278 cmd.FlagWithInput("--baseline ", baselinePath.Path())
279 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
280 }
281 }
282
Colin Cross31972dc2021-03-04 10:44:12 -0800283 return lintPaths{
284 projectXML: projectXMLPath,
285 configXML: configXMLPath,
286 cacheDir: cacheDir,
287 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800288 }
289
Colin Cross014489c2020-06-02 20:09:13 -0700290}
291
Liz Kammer20ebfb42020-07-28 11:32:07 -0700292// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700293// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800294func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700295 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
296
297 rule.Command().Text("(").
298 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
299 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
300 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
301 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
302 l.minSdkVersion, l.targetSdkVersion).
303 Text(`echo "</manifest>"`).
304 Text(") >").Output(manifestPath)
305
306 return manifestPath
307}
308
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700309func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
310 var lintBaseline android.OptionalPath
311 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
312 if String(l.properties.Lint.Baseline_filename) != "" {
313 // if manually specified, we require the file to exist
314 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
315 } else {
316 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
317 }
318 }
319 return lintBaseline
320}
321
Colin Cross014489c2020-06-02 20:09:13 -0700322func (l *linter) lint(ctx android.ModuleContext) {
323 if !l.enabled() {
324 return
325 }
326
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000327 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700328 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
329 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
330 if len(filtered) != 0 {
331 ctx.PropertyErrorf("lint.warning_checks",
332 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
333 }
334 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
335 if len(filtered) != 0 {
336 ctx.PropertyErrorf("lint.disabled_checks",
337 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
338 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000339 }
340
Colin Cross92e4b462020-06-18 15:56:48 -0700341 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
342 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800343 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
344 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
345 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700346 } else {
347 ctx.PropertyErrorf("lint.extra_check_modules",
348 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
349 }
350 }
351
Colin Cross1661aff2021-03-12 17:56:51 -0800352 rule := android.NewRuleBuilder(pctx, ctx).
353 Sbox(android.PathForModuleOut(ctx, "lint"),
354 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
355 SandboxInputs()
356
357 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
358 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
359 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
360 rule.Rewrapper(&remoteexec.REParams{
361 Labels: map[string]string{"type": "tool", "name": "lint"},
362 ExecStrategy: lintRBEExecStrategy(ctx),
363 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
Colin Cross95fad7a2021-06-09 12:48:53 -0700364 Platform: map[string]string{remoteexec.PoolKey: pool},
Colin Cross1661aff2021-03-12 17:56:51 -0800365 })
366 }
Colin Cross014489c2020-06-02 20:09:13 -0700367
368 if l.manifest == nil {
369 manifest := l.generateManifest(ctx, rule)
370 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800371 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700372 }
373
Colin Cross31972dc2021-03-04 10:44:12 -0800374 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700375
Colin Cross1661aff2021-03-12 17:56:51 -0800376 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
377 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
378 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700379
Colin Cross08dca382020-07-21 20:31:17 -0700380 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700381
382 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700383 if depLint, ok := dep.(lintDepSetsIntf); ok {
384 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700385 }
386 })
Colin Cross014489c2020-06-02 20:09:13 -0700387
Colin Cross31972dc2021-03-04 10:44:12 -0800388 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
389 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800390 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700391
Colin Cross8a6ed372020-07-06 11:45:51 -0700392 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900393 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700394 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
395 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
396 } else {
397 annotationsZipPath = copiedAnnotationsZipPath(ctx)
398 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
399 }
400
Colin Cross31972dc2021-03-04 10:44:12 -0800401 cmd := rule.Command()
402
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000403 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800404 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700405 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800406 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
407
Colin Cross1661aff2021-03-12 17:56:51 -0800408 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700409 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800410 FlagWithInput("--project ", lintPaths.projectXML).
411 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700412 FlagWithOutput("--html ", html).
413 FlagWithOutput("--text ", text).
414 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700415 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
416 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
417 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
418 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
419 Flag("--exitcode").
420 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800421 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700422 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700423
Colin Cross1661aff2021-03-12 17:56:51 -0800424 rule.Temporary(lintPaths.projectXML)
425 rule.Temporary(lintPaths.configXML)
426
Colin Cross988dfcc2020-07-16 17:32:17 -0700427 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
428 cmd.FlagWithArg("--check ", checkOnly)
429 }
430
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700431 lintBaseline := l.getBaselineFilepath(ctx)
432 if lintBaseline.Valid() {
433 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000434 }
435
Colin Cross31972dc2021-03-04 10:44:12 -0800436 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700437
Colin Cross31972dc2021-03-04 10:44:12 -0800438 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700439
Colin Crossee4a8b72021-04-05 18:38:05 -0700440 // The HTML output contains a date, remove it to make the output deterministic.
441 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
442
Colin Crossf1a035e2020-11-16 17:32:30 -0800443 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700444
Colin Crossc0efd1d2020-07-03 11:56:24 -0700445 l.outputs = lintOutputs{
446 html: html,
447 text: text,
448 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700449
Colin Cross08dca382020-07-21 20:31:17 -0700450 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700451 }
Colin Cross014489c2020-06-02 20:09:13 -0700452
Colin Crossc0efd1d2020-07-03 11:56:24 -0700453 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700454 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700455 }
456}
Colin Cross014489c2020-06-02 20:09:13 -0700457
Colin Cross08dca382020-07-21 20:31:17 -0700458func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
459 htmlList := depSets.HTML.ToSortedList()
460 textList := depSets.Text.ToSortedList()
461 xmlList := depSets.XML.ToSortedList()
462
463 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
464 return nil
465 }
466
467 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
468 lintZip(ctx, htmlList, htmlZip)
469
470 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
471 lintZip(ctx, textList, textZip)
472
473 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
474 lintZip(ctx, xmlList, xmlZip)
475
476 return android.Paths{htmlZip, textZip, xmlZip}
477}
478
Colin Cross014489c2020-06-02 20:09:13 -0700479type lintSingleton struct {
480 htmlZip android.WritablePath
481 textZip android.WritablePath
482 xmlZip android.WritablePath
483}
484
485func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
486 l.generateLintReportZips(ctx)
487 l.copyLintDependencies(ctx)
488}
489
490func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900491 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700492 return
493 }
494
495 var frameworkDocStubs android.Module
496 ctx.VisitAllModules(func(m android.Module) {
497 if ctx.ModuleName(m) == "framework-doc-stubs" {
498 if frameworkDocStubs == nil {
499 frameworkDocStubs = m
500 } else {
501 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
502 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
503 }
504 }
505 })
506
507 if frameworkDocStubs == nil {
508 if !ctx.Config().AllowMissingDependencies() {
509 ctx.Errorf("lint: missing framework-doc-stubs")
510 }
511 return
512 }
513
514 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800515 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700516 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700517 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700518 })
519
520 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800521 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700522 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700523 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700524 })
525}
526
Colin Cross8a6ed372020-07-06 11:45:51 -0700527func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700528 return android.PathForOutput(ctx, "lint", "annotations.zip")
529}
530
Colin Cross8a6ed372020-07-06 11:45:51 -0700531func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700532 return android.PathForOutput(ctx, "lint", "api_versions.xml")
533}
534
535func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700536 if ctx.Config().UnbundledBuild() {
537 return
538 }
539
Colin Cross014489c2020-06-02 20:09:13 -0700540 var outputs []*lintOutputs
541 var dirs []string
542 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500543 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700544 return
545 }
546
Colin Cross56a83212020-09-15 18:30:11 -0700547 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
548 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
549 if apexInfo.IsForPlatform() {
550 // There are stray platform variants of modules in apexes that are not available for
551 // the platform, and they sometimes can't be built. Don't depend on them.
552 return
553 }
Colin Cross014489c2020-06-02 20:09:13 -0700554 }
555
Colin Cross08dca382020-07-21 20:31:17 -0700556 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700557 outputs = append(outputs, l.lintOutputs())
558 }
559 })
560
561 dirs = android.SortedUniqueStrings(dirs)
562
563 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
564 var paths android.Paths
565
566 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700567 if p := get(output); p != nil {
568 paths = append(paths, p)
569 }
Colin Cross014489c2020-06-02 20:09:13 -0700570 }
571
Colin Crossc0efd1d2020-07-03 11:56:24 -0700572 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700573 }
574
575 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
576 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
577
578 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
579 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
580
581 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
582 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
583
584 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
585}
586
587func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700588 if !ctx.Config().UnbundledBuild() {
589 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
590 }
Colin Cross014489c2020-06-02 20:09:13 -0700591}
592
593var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
594
595func init() {
596 android.RegisterSingletonType("lint",
597 func() android.Singleton { return &lintSingleton{} })
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700598
599 registerLintBuildComponents(android.InitRegistrationContext)
600}
601
602func registerLintBuildComponents(ctx android.RegistrationContext) {
603 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
604 ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
605 })
Colin Cross014489c2020-06-02 20:09:13 -0700606}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700607
608func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
609 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
610
611 sort.Slice(paths, func(i, j int) bool {
612 return paths[i].String() < paths[j].String()
613 })
614
Colin Crossf1a035e2020-11-16 17:32:30 -0800615 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700616
Colin Crossf1a035e2020-11-16 17:32:30 -0800617 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700618 FlagWithOutput("-o ", outputPath).
619 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800620 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700621
Colin Crossf1a035e2020-11-16 17:32:30 -0800622 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700623}
Jaewoong Jung476b9d62021-05-10 15:30:00 -0700624
625// Enforce the strict updatability linting to all applicable transitive dependencies.
626func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
627 m := ctx.Module()
628 if d, ok := m.(lintDepSetsIntf); ok && d.getStrictUpdatabilityLinting() {
629 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
630 if a, ok := d.(lintDepSetsIntf); ok {
631 a.setStrictUpdatabilityLinting(true)
632 }
633 })
634 }
635}