blob: 862c9b4d99785ecda35bccff5918089d2abf5eb6 [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) {
264 if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
265 cmd.FlagWithInput("--baseline ", baselinePath.Path())
266 cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
267 }
268 }
269
Colin Cross31972dc2021-03-04 10:44:12 -0800270 return lintPaths{
271 projectXML: projectXMLPath,
272 configXML: configXMLPath,
273 cacheDir: cacheDir,
274 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800275 }
276
Colin Cross014489c2020-06-02 20:09:13 -0700277}
278
Liz Kammer20ebfb42020-07-28 11:32:07 -0700279// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700280// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800281func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700282 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
283
284 rule.Command().Text("(").
285 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
286 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
287 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
288 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
289 l.minSdkVersion, l.targetSdkVersion).
290 Text(`echo "</manifest>"`).
291 Text(") >").Output(manifestPath)
292
293 return manifestPath
294}
295
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700296func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
297 var lintBaseline android.OptionalPath
298 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
299 if String(l.properties.Lint.Baseline_filename) != "" {
300 // if manually specified, we require the file to exist
301 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
302 } else {
303 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
304 }
305 }
306 return lintBaseline
307}
308
Colin Cross014489c2020-06-02 20:09:13 -0700309func (l *linter) lint(ctx android.ModuleContext) {
310 if !l.enabled() {
311 return
312 }
313
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000314 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700315 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
316 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
317 if len(filtered) != 0 {
318 ctx.PropertyErrorf("lint.warning_checks",
319 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
320 }
321 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
322 if len(filtered) != 0 {
323 ctx.PropertyErrorf("lint.disabled_checks",
324 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
325 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000326 }
327
Colin Cross92e4b462020-06-18 15:56:48 -0700328 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
329 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800330 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
331 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
332 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700333 } else {
334 ctx.PropertyErrorf("lint.extra_check_modules",
335 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
336 }
337 }
338
Colin Cross1661aff2021-03-12 17:56:51 -0800339 rule := android.NewRuleBuilder(pctx, ctx).
340 Sbox(android.PathForModuleOut(ctx, "lint"),
341 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
342 SandboxInputs()
343
344 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
345 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
346 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
347 rule.Rewrapper(&remoteexec.REParams{
348 Labels: map[string]string{"type": "tool", "name": "lint"},
349 ExecStrategy: lintRBEExecStrategy(ctx),
350 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
351 EnvironmentVariables: []string{
352 "LANG",
353 },
354 Platform: map[string]string{remoteexec.PoolKey: pool},
355 })
356 }
Colin Cross014489c2020-06-02 20:09:13 -0700357
358 if l.manifest == nil {
359 manifest := l.generateManifest(ctx, rule)
360 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800361 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700362 }
363
Colin Cross31972dc2021-03-04 10:44:12 -0800364 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700365
Colin Cross1661aff2021-03-12 17:56:51 -0800366 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
367 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
368 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700369
Colin Cross08dca382020-07-21 20:31:17 -0700370 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700371
372 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700373 if depLint, ok := dep.(lintDepSetsIntf); ok {
374 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700375 }
376 })
Colin Cross014489c2020-06-02 20:09:13 -0700377
Colin Cross31972dc2021-03-04 10:44:12 -0800378 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
379 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800380 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700381
Colin Cross8a6ed372020-07-06 11:45:51 -0700382 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900383 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700384 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
385 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
386 } else {
387 annotationsZipPath = copiedAnnotationsZipPath(ctx)
388 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
389 }
390
Colin Cross31972dc2021-03-04 10:44:12 -0800391 cmd := rule.Command()
392
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000393 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800394 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700395 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800396 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
397
Colin Cross1661aff2021-03-12 17:56:51 -0800398 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700399 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800400 FlagWithInput("--project ", lintPaths.projectXML).
401 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700402 FlagWithOutput("--html ", html).
403 FlagWithOutput("--text ", text).
404 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700405 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
406 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
407 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
408 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
409 Flag("--exitcode").
410 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800411 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700412 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700413
Colin Cross1661aff2021-03-12 17:56:51 -0800414 rule.Temporary(lintPaths.projectXML)
415 rule.Temporary(lintPaths.configXML)
416
Colin Cross988dfcc2020-07-16 17:32:17 -0700417 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
418 cmd.FlagWithArg("--check ", checkOnly)
419 }
420
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700421 lintBaseline := l.getBaselineFilepath(ctx)
422 if lintBaseline.Valid() {
423 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000424 }
425
Colin Cross31972dc2021-03-04 10:44:12 -0800426 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700427
Colin Cross31972dc2021-03-04 10:44:12 -0800428 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700429
Colin Crossee4a8b72021-04-05 18:38:05 -0700430 // The HTML output contains a date, remove it to make the output deterministic.
431 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
432
Colin Crossf1a035e2020-11-16 17:32:30 -0800433 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700434
Colin Crossc0efd1d2020-07-03 11:56:24 -0700435 l.outputs = lintOutputs{
436 html: html,
437 text: text,
438 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700439
Colin Cross08dca382020-07-21 20:31:17 -0700440 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700441 }
Colin Cross014489c2020-06-02 20:09:13 -0700442
Colin Crossc0efd1d2020-07-03 11:56:24 -0700443 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700444 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700445 }
446}
Colin Cross014489c2020-06-02 20:09:13 -0700447
Colin Cross08dca382020-07-21 20:31:17 -0700448func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
449 htmlList := depSets.HTML.ToSortedList()
450 textList := depSets.Text.ToSortedList()
451 xmlList := depSets.XML.ToSortedList()
452
453 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
454 return nil
455 }
456
457 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
458 lintZip(ctx, htmlList, htmlZip)
459
460 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
461 lintZip(ctx, textList, textZip)
462
463 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
464 lintZip(ctx, xmlList, xmlZip)
465
466 return android.Paths{htmlZip, textZip, xmlZip}
467}
468
Colin Cross014489c2020-06-02 20:09:13 -0700469type lintSingleton struct {
470 htmlZip android.WritablePath
471 textZip android.WritablePath
472 xmlZip android.WritablePath
473}
474
475func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
476 l.generateLintReportZips(ctx)
477 l.copyLintDependencies(ctx)
478}
479
480func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900481 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700482 return
483 }
484
485 var frameworkDocStubs android.Module
486 ctx.VisitAllModules(func(m android.Module) {
487 if ctx.ModuleName(m) == "framework-doc-stubs" {
488 if frameworkDocStubs == nil {
489 frameworkDocStubs = m
490 } else {
491 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
492 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
493 }
494 }
495 })
496
497 if frameworkDocStubs == nil {
498 if !ctx.Config().AllowMissingDependencies() {
499 ctx.Errorf("lint: missing framework-doc-stubs")
500 }
501 return
502 }
503
504 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800505 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700506 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700507 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700508 })
509
510 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800511 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700512 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700513 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700514 })
515}
516
Colin Cross8a6ed372020-07-06 11:45:51 -0700517func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700518 return android.PathForOutput(ctx, "lint", "annotations.zip")
519}
520
Colin Cross8a6ed372020-07-06 11:45:51 -0700521func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700522 return android.PathForOutput(ctx, "lint", "api_versions.xml")
523}
524
525func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700526 if ctx.Config().UnbundledBuild() {
527 return
528 }
529
Colin Cross014489c2020-06-02 20:09:13 -0700530 var outputs []*lintOutputs
531 var dirs []string
532 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500533 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700534 return
535 }
536
Colin Cross56a83212020-09-15 18:30:11 -0700537 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
538 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
539 if apexInfo.IsForPlatform() {
540 // There are stray platform variants of modules in apexes that are not available for
541 // the platform, and they sometimes can't be built. Don't depend on them.
542 return
543 }
Colin Cross014489c2020-06-02 20:09:13 -0700544 }
545
Colin Cross08dca382020-07-21 20:31:17 -0700546 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700547 outputs = append(outputs, l.lintOutputs())
548 }
549 })
550
551 dirs = android.SortedUniqueStrings(dirs)
552
553 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
554 var paths android.Paths
555
556 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700557 if p := get(output); p != nil {
558 paths = append(paths, p)
559 }
Colin Cross014489c2020-06-02 20:09:13 -0700560 }
561
Colin Crossc0efd1d2020-07-03 11:56:24 -0700562 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700563 }
564
565 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
566 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
567
568 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
569 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
570
571 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
572 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
573
574 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
575}
576
577func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700578 if !ctx.Config().UnbundledBuild() {
579 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
580 }
Colin Cross014489c2020-06-02 20:09:13 -0700581}
582
583var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
584
585func init() {
586 android.RegisterSingletonType("lint",
587 func() android.Singleton { return &lintSingleton{} })
588}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700589
590func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
591 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
592
593 sort.Slice(paths, func(i, j int) bool {
594 return paths[i].String() < paths[j].String()
595 })
596
Colin Crossf1a035e2020-11-16 17:32:30 -0800597 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700598
Colin Crossf1a035e2020-11-16 17:32:30 -0800599 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700600 FlagWithOutput("-o ", outputPath).
601 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800602 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700603
Colin Crossf1a035e2020-11-16 17:32:30 -0800604 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700605}