blob: 5e392742c6d51d6b05336458f9294dd4e863d2e7 [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
106}
107
108type LintDepSets struct {
109 HTML, Text, XML *android.DepSet
110}
111
112type LintDepSetsBuilder struct {
113 HTML, Text, XML *android.DepSetBuilder
114}
115
116func NewLintDepSetBuilder() LintDepSetsBuilder {
117 return LintDepSetsBuilder{
118 HTML: android.NewDepSetBuilder(android.POSTORDER),
119 Text: android.NewDepSetBuilder(android.POSTORDER),
120 XML: android.NewDepSetBuilder(android.POSTORDER),
121 }
122}
123
124func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
125 l.HTML.Direct(html)
126 l.Text.Direct(text)
127 l.XML.Direct(xml)
128 return l
129}
130
131func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
132 if depSets.HTML != nil {
133 l.HTML.Transitive(depSets.HTML)
134 }
135 if depSets.Text != nil {
136 l.Text.Transitive(depSets.Text)
137 }
138 if depSets.XML != nil {
139 l.XML.Transitive(depSets.XML)
140 }
141 return l
142}
143
144func (l LintDepSetsBuilder) Build() LintDepSets {
145 return LintDepSets{
146 HTML: l.HTML.Build(),
147 Text: l.Text.Build(),
148 XML: l.XML.Build(),
149 }
150}
151
152func (l *linter) LintDepSets() LintDepSets {
153 return l.outputs.depSets
154}
155
156var _ lintDepSetsIntf = (*linter)(nil)
157
158var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700159
160func (l *linter) lintOutputs() *lintOutputs {
161 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700162}
163
164func (l *linter) enabled() bool {
165 return BoolDefault(l.properties.Lint.Enabled, true)
166}
167
Colin Cross92e4b462020-06-18 15:56:48 -0700168func (l *linter) deps(ctx android.BottomUpMutatorContext) {
169 if !l.enabled() {
170 return
171 }
172
Colin Cross988dfcc2020-07-16 17:32:17 -0700173 extraCheckModules := l.properties.Lint.Extra_check_modules
174
175 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
176 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
177 extraCheckModules = strings.Split(checkOnlyModules, ",")
178 }
179 }
180
181 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
182 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700183}
184
Colin Crossad22bc22021-03-10 09:45:40 -0800185// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
186// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800187type lintPaths struct {
188 projectXML android.WritablePath
189 configXML android.WritablePath
190 cacheDir android.WritablePath
191 homeDir android.WritablePath
192 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800193}
194
Colin Cross9b93af42021-03-10 10:40:58 -0800195func lintRBEExecStrategy(ctx android.ModuleContext) string {
196 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
197}
198
Colin Cross31972dc2021-03-04 10:44:12 -0800199func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800200 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700201 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800202 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
203 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
204 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700205
Colin Cross1661aff2021-03-12 17:56:51 -0800206 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700207 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
208
209 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700210 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700211 FlagWithOutput("--project_out ", projectXMLPath).
212 FlagWithOutput("--config_out ", configXMLPath).
213 FlagWithArg("--name ", ctx.ModuleName())
214
215 if l.library {
216 cmd.Flag("--library")
217 }
218 if l.test {
219 cmd.Flag("--test")
220 }
221 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700222 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700223 }
224 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700225 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700226 }
227
Colin Cross5bedfa22021-03-23 17:07:14 -0700228 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
229 // lint separately.
230 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
231 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
Colin Cross014489c2020-06-02 20:09:13 -0700232
233 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700234
Colin Cross5bedfa22021-03-23 17:07:14 -0700235 if len(l.resources) > 0 {
236 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
237 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700238 }
239
240 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700241 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700242 }
243
Colin Cross5bedfa22021-03-23 17:07:14 -0700244 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700245
Colin Cross5bedfa22021-03-23 17:07:14 -0700246 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700247
Colin Cross1661aff2021-03-12 17:56:51 -0800248 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700249
250 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
251 // the root dir is not set.
252 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700253
254 cmd.FlagWithInput("@",
255 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
256
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000257 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700258 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
259 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
260 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
261 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
262
Jaewoong Jung48de8832021-04-21 16:17:25 -0700263 if BoolDefault(l.properties.Lint.Strict_updatability_linting, false) {
Jaewoong Jung3c87b1d2021-04-22 11:01:36 -0700264 // Verify the module does not baseline issues that endanger safe updatability.
Jaewoong Jung48de8832021-04-21 16:17:25 -0700265 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
266 cmd.FlagWithInput("--baseline ", baselinePath.Path())
267 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
268 }
269 }
270
Colin Cross31972dc2021-03-04 10:44:12 -0800271 return lintPaths{
272 projectXML: projectXMLPath,
273 configXML: configXMLPath,
274 cacheDir: cacheDir,
275 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800276 }
277
Colin Cross014489c2020-06-02 20:09:13 -0700278}
279
Liz Kammer20ebfb42020-07-28 11:32:07 -0700280// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700281// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800282func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700283 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
284
285 rule.Command().Text("(").
286 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
287 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
288 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
289 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
290 l.minSdkVersion, l.targetSdkVersion).
291 Text(`echo "</manifest>"`).
292 Text(") >").Output(manifestPath)
293
294 return manifestPath
295}
296
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700297func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
298 var lintBaseline android.OptionalPath
299 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
300 if String(l.properties.Lint.Baseline_filename) != "" {
301 // if manually specified, we require the file to exist
302 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
303 } else {
304 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
305 }
306 }
307 return lintBaseline
308}
309
Colin Cross014489c2020-06-02 20:09:13 -0700310func (l *linter) lint(ctx android.ModuleContext) {
311 if !l.enabled() {
312 return
313 }
314
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000315 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700316 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
317 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
318 if len(filtered) != 0 {
319 ctx.PropertyErrorf("lint.warning_checks",
320 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
321 }
322 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
323 if len(filtered) != 0 {
324 ctx.PropertyErrorf("lint.disabled_checks",
325 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
326 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000327 }
328
Colin Cross92e4b462020-06-18 15:56:48 -0700329 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
330 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800331 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
332 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
333 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700334 } else {
335 ctx.PropertyErrorf("lint.extra_check_modules",
336 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
337 }
338 }
339
Colin Cross1661aff2021-03-12 17:56:51 -0800340 rule := android.NewRuleBuilder(pctx, ctx).
341 Sbox(android.PathForModuleOut(ctx, "lint"),
342 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
343 SandboxInputs()
344
345 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
346 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
347 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
348 rule.Rewrapper(&remoteexec.REParams{
349 Labels: map[string]string{"type": "tool", "name": "lint"},
350 ExecStrategy: lintRBEExecStrategy(ctx),
351 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
352 EnvironmentVariables: []string{
353 "LANG",
354 },
355 Platform: map[string]string{remoteexec.PoolKey: pool},
356 })
357 }
Colin Cross014489c2020-06-02 20:09:13 -0700358
359 if l.manifest == nil {
360 manifest := l.generateManifest(ctx, rule)
361 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800362 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700363 }
364
Colin Cross31972dc2021-03-04 10:44:12 -0800365 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700366
Colin Cross1661aff2021-03-12 17:56:51 -0800367 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
368 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
369 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700370
Colin Cross08dca382020-07-21 20:31:17 -0700371 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700372
373 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700374 if depLint, ok := dep.(lintDepSetsIntf); ok {
375 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700376 }
377 })
Colin Cross014489c2020-06-02 20:09:13 -0700378
Colin Cross31972dc2021-03-04 10:44:12 -0800379 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
380 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800381 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700382
Colin Cross8a6ed372020-07-06 11:45:51 -0700383 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900384 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700385 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
386 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
387 } else {
388 annotationsZipPath = copiedAnnotationsZipPath(ctx)
389 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
390 }
391
Colin Cross31972dc2021-03-04 10:44:12 -0800392 cmd := rule.Command()
393
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000394 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800395 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700396 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800397 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
398
Colin Cross1661aff2021-03-12 17:56:51 -0800399 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700400 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800401 FlagWithInput("--project ", lintPaths.projectXML).
402 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700403 FlagWithOutput("--html ", html).
404 FlagWithOutput("--text ", text).
405 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700406 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
407 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
408 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
409 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
410 Flag("--exitcode").
411 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800412 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700413 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700414
Colin Cross1661aff2021-03-12 17:56:51 -0800415 rule.Temporary(lintPaths.projectXML)
416 rule.Temporary(lintPaths.configXML)
417
Colin Cross988dfcc2020-07-16 17:32:17 -0700418 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
419 cmd.FlagWithArg("--check ", checkOnly)
420 }
421
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700422 lintBaseline := l.getBaselineFilepath(ctx)
423 if lintBaseline.Valid() {
424 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000425 }
426
Colin Cross31972dc2021-03-04 10:44:12 -0800427 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700428
Colin Cross31972dc2021-03-04 10:44:12 -0800429 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700430
Colin Crossee4a8b72021-04-05 18:38:05 -0700431 // The HTML output contains a date, remove it to make the output deterministic.
432 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
433
Colin Crossf1a035e2020-11-16 17:32:30 -0800434 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700435
Colin Crossc0efd1d2020-07-03 11:56:24 -0700436 l.outputs = lintOutputs{
437 html: html,
438 text: text,
439 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700440
Colin Cross08dca382020-07-21 20:31:17 -0700441 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700442 }
Colin Cross014489c2020-06-02 20:09:13 -0700443
Colin Crossc0efd1d2020-07-03 11:56:24 -0700444 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700445 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700446 }
447}
Colin Cross014489c2020-06-02 20:09:13 -0700448
Colin Cross08dca382020-07-21 20:31:17 -0700449func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
450 htmlList := depSets.HTML.ToSortedList()
451 textList := depSets.Text.ToSortedList()
452 xmlList := depSets.XML.ToSortedList()
453
454 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
455 return nil
456 }
457
458 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
459 lintZip(ctx, htmlList, htmlZip)
460
461 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
462 lintZip(ctx, textList, textZip)
463
464 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
465 lintZip(ctx, xmlList, xmlZip)
466
467 return android.Paths{htmlZip, textZip, xmlZip}
468}
469
Colin Cross014489c2020-06-02 20:09:13 -0700470type lintSingleton struct {
471 htmlZip android.WritablePath
472 textZip android.WritablePath
473 xmlZip android.WritablePath
474}
475
476func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
477 l.generateLintReportZips(ctx)
478 l.copyLintDependencies(ctx)
479}
480
481func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900482 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700483 return
484 }
485
486 var frameworkDocStubs android.Module
487 ctx.VisitAllModules(func(m android.Module) {
488 if ctx.ModuleName(m) == "framework-doc-stubs" {
489 if frameworkDocStubs == nil {
490 frameworkDocStubs = m
491 } else {
492 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
493 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
494 }
495 }
496 })
497
498 if frameworkDocStubs == nil {
499 if !ctx.Config().AllowMissingDependencies() {
500 ctx.Errorf("lint: missing framework-doc-stubs")
501 }
502 return
503 }
504
505 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800506 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700507 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700508 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700509 })
510
511 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800512 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700513 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700514 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700515 })
516}
517
Colin Cross8a6ed372020-07-06 11:45:51 -0700518func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700519 return android.PathForOutput(ctx, "lint", "annotations.zip")
520}
521
Colin Cross8a6ed372020-07-06 11:45:51 -0700522func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700523 return android.PathForOutput(ctx, "lint", "api_versions.xml")
524}
525
526func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700527 if ctx.Config().UnbundledBuild() {
528 return
529 }
530
Colin Cross014489c2020-06-02 20:09:13 -0700531 var outputs []*lintOutputs
532 var dirs []string
533 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500534 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700535 return
536 }
537
Colin Cross56a83212020-09-15 18:30:11 -0700538 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
539 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
540 if apexInfo.IsForPlatform() {
541 // There are stray platform variants of modules in apexes that are not available for
542 // the platform, and they sometimes can't be built. Don't depend on them.
543 return
544 }
Colin Cross014489c2020-06-02 20:09:13 -0700545 }
546
Colin Cross08dca382020-07-21 20:31:17 -0700547 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700548 outputs = append(outputs, l.lintOutputs())
549 }
550 })
551
552 dirs = android.SortedUniqueStrings(dirs)
553
554 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
555 var paths android.Paths
556
557 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700558 if p := get(output); p != nil {
559 paths = append(paths, p)
560 }
Colin Cross014489c2020-06-02 20:09:13 -0700561 }
562
Colin Crossc0efd1d2020-07-03 11:56:24 -0700563 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700564 }
565
566 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
567 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
568
569 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
570 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
571
572 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
573 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
574
575 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
576}
577
578func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700579 if !ctx.Config().UnbundledBuild() {
580 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
581 }
Colin Cross014489c2020-06-02 20:09:13 -0700582}
583
584var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
585
586func init() {
587 android.RegisterSingletonType("lint",
588 func() android.Singleton { return &lintSingleton{} })
589}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700590
591func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
592 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
593
594 sort.Slice(paths, func(i, j int) bool {
595 return paths[i].String() < paths[j].String()
596 })
597
Colin Crossf1a035e2020-11-16 17:32:30 -0800598 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700599
Colin Crossf1a035e2020-11-16 17:32:30 -0800600 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700601 FlagWithOutput("-o ", outputPath).
602 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800603 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700604
Colin Crossf1a035e2020-11-16 17:32:30 -0800605 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700606}