blob: 0618cbf6d86f5c2aaf20921f92b4b056ac9b4c6c [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
Colin Cross014489c2020-06-02 20:09:13 -070060 }
61}
62
63type linter struct {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000064 name string
65 manifest android.Path
66 mergedManifest android.Path
67 srcs android.Paths
68 srcJars android.Paths
69 resources android.Paths
70 classpath android.Paths
71 classes android.Path
72 extraLintCheckJars android.Paths
73 test bool
74 library bool
75 minSdkVersion string
76 targetSdkVersion string
77 compileSdkVersion string
78 javaLanguageLevel string
79 kotlinLanguageLevel string
80 outputs lintOutputs
81 properties LintProperties
82 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070083
Colin Cross08dca382020-07-21 20:31:17 -070084 reports android.Paths
85
Colin Crossc0efd1d2020-07-03 11:56:24 -070086 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070087}
88
89type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070090 html android.Path
91 text android.Path
92 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070093
Colin Cross08dca382020-07-21 20:31:17 -070094 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -070095}
96
Colin Cross08dca382020-07-21 20:31:17 -070097type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -070098 lintOutputs() *lintOutputs
99}
100
Colin Cross08dca382020-07-21 20:31:17 -0700101type lintDepSetsIntf interface {
102 LintDepSets() LintDepSets
103}
104
105type LintDepSets struct {
106 HTML, Text, XML *android.DepSet
107}
108
109type LintDepSetsBuilder struct {
110 HTML, Text, XML *android.DepSetBuilder
111}
112
113func NewLintDepSetBuilder() LintDepSetsBuilder {
114 return LintDepSetsBuilder{
115 HTML: android.NewDepSetBuilder(android.POSTORDER),
116 Text: android.NewDepSetBuilder(android.POSTORDER),
117 XML: android.NewDepSetBuilder(android.POSTORDER),
118 }
119}
120
121func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
122 l.HTML.Direct(html)
123 l.Text.Direct(text)
124 l.XML.Direct(xml)
125 return l
126}
127
128func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
129 if depSets.HTML != nil {
130 l.HTML.Transitive(depSets.HTML)
131 }
132 if depSets.Text != nil {
133 l.Text.Transitive(depSets.Text)
134 }
135 if depSets.XML != nil {
136 l.XML.Transitive(depSets.XML)
137 }
138 return l
139}
140
141func (l LintDepSetsBuilder) Build() LintDepSets {
142 return LintDepSets{
143 HTML: l.HTML.Build(),
144 Text: l.Text.Build(),
145 XML: l.XML.Build(),
146 }
147}
148
149func (l *linter) LintDepSets() LintDepSets {
150 return l.outputs.depSets
151}
152
153var _ lintDepSetsIntf = (*linter)(nil)
154
155var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700156
157func (l *linter) lintOutputs() *lintOutputs {
158 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700159}
160
161func (l *linter) enabled() bool {
162 return BoolDefault(l.properties.Lint.Enabled, true)
163}
164
Colin Cross92e4b462020-06-18 15:56:48 -0700165func (l *linter) deps(ctx android.BottomUpMutatorContext) {
166 if !l.enabled() {
167 return
168 }
169
Colin Cross988dfcc2020-07-16 17:32:17 -0700170 extraCheckModules := l.properties.Lint.Extra_check_modules
171
172 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
173 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
174 extraCheckModules = strings.Split(checkOnlyModules, ",")
175 }
176 }
177
178 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
179 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700180}
181
Colin Crossad22bc22021-03-10 09:45:40 -0800182// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
183// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800184type lintPaths struct {
185 projectXML android.WritablePath
186 configXML android.WritablePath
187 cacheDir android.WritablePath
188 homeDir android.WritablePath
189 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800190}
191
Colin Cross9b93af42021-03-10 10:40:58 -0800192func lintRBEExecStrategy(ctx android.ModuleContext) string {
193 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
194}
195
Colin Cross31972dc2021-03-04 10:44:12 -0800196func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800197 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700198 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800199 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
200 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
201 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700202
Colin Cross1661aff2021-03-12 17:56:51 -0800203 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700204 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
205
206 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700207 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700208 FlagWithOutput("--project_out ", projectXMLPath).
209 FlagWithOutput("--config_out ", configXMLPath).
210 FlagWithArg("--name ", ctx.ModuleName())
211
212 if l.library {
213 cmd.Flag("--library")
214 }
215 if l.test {
216 cmd.Flag("--test")
217 }
218 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700219 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700220 }
221 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700222 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700223 }
224
Colin Cross5bedfa22021-03-23 17:07:14 -0700225 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
226 // lint separately.
227 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
228 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
Colin Cross014489c2020-06-02 20:09:13 -0700229
230 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700231
Colin Cross5bedfa22021-03-23 17:07:14 -0700232 if len(l.resources) > 0 {
233 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
234 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700235 }
236
237 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700238 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700239 }
240
Colin Cross5bedfa22021-03-23 17:07:14 -0700241 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700242
Colin Cross5bedfa22021-03-23 17:07:14 -0700243 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700244
Colin Cross1661aff2021-03-12 17:56:51 -0800245 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700246
247 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
248 // the root dir is not set.
249 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700250
251 cmd.FlagWithInput("@",
252 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
253
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000254 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700255 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
256 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
257 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
258 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
259
Colin Cross31972dc2021-03-04 10:44:12 -0800260 return lintPaths{
261 projectXML: projectXMLPath,
262 configXML: configXMLPath,
263 cacheDir: cacheDir,
264 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800265 }
266
Colin Cross014489c2020-06-02 20:09:13 -0700267}
268
Liz Kammer20ebfb42020-07-28 11:32:07 -0700269// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700270// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800271func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700272 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
273
274 rule.Command().Text("(").
275 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
276 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
277 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
278 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
279 l.minSdkVersion, l.targetSdkVersion).
280 Text(`echo "</manifest>"`).
281 Text(") >").Output(manifestPath)
282
283 return manifestPath
284}
285
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700286func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
287 var lintBaseline android.OptionalPath
288 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
289 if String(l.properties.Lint.Baseline_filename) != "" {
290 // if manually specified, we require the file to exist
291 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
292 } else {
293 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
294 }
295 }
296 return lintBaseline
297}
298
Colin Cross014489c2020-06-02 20:09:13 -0700299func (l *linter) lint(ctx android.ModuleContext) {
300 if !l.enabled() {
301 return
302 }
303
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000304 if l.minSdkVersion != l.compileSdkVersion {
Jaewoong Jung79e6f6b2021-04-21 14:01:55 -0700305 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
306 _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
307 if len(filtered) != 0 {
308 ctx.PropertyErrorf("lint.warning_checks",
309 "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
310 }
311 _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
312 if len(filtered) != 0 {
313 ctx.PropertyErrorf("lint.disabled_checks",
314 "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
315 }
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000316 }
317
Colin Cross92e4b462020-06-18 15:56:48 -0700318 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
319 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800320 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
321 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
322 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700323 } else {
324 ctx.PropertyErrorf("lint.extra_check_modules",
325 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
326 }
327 }
328
Colin Cross1661aff2021-03-12 17:56:51 -0800329 rule := android.NewRuleBuilder(pctx, ctx).
330 Sbox(android.PathForModuleOut(ctx, "lint"),
331 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
332 SandboxInputs()
333
334 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
335 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
336 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
337 rule.Rewrapper(&remoteexec.REParams{
338 Labels: map[string]string{"type": "tool", "name": "lint"},
339 ExecStrategy: lintRBEExecStrategy(ctx),
340 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
341 EnvironmentVariables: []string{
342 "LANG",
343 },
344 Platform: map[string]string{remoteexec.PoolKey: pool},
345 })
346 }
Colin Cross014489c2020-06-02 20:09:13 -0700347
348 if l.manifest == nil {
349 manifest := l.generateManifest(ctx, rule)
350 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800351 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700352 }
353
Colin Cross31972dc2021-03-04 10:44:12 -0800354 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700355
Colin Cross1661aff2021-03-12 17:56:51 -0800356 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
357 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
358 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700359
Colin Cross08dca382020-07-21 20:31:17 -0700360 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700361
362 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700363 if depLint, ok := dep.(lintDepSetsIntf); ok {
364 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700365 }
366 })
Colin Cross014489c2020-06-02 20:09:13 -0700367
Colin Cross31972dc2021-03-04 10:44:12 -0800368 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
369 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800370 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700371
Colin Cross8a6ed372020-07-06 11:45:51 -0700372 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900373 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700374 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
375 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
376 } else {
377 annotationsZipPath = copiedAnnotationsZipPath(ctx)
378 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
379 }
380
Colin Cross31972dc2021-03-04 10:44:12 -0800381 cmd := rule.Command()
382
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000383 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800384 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700385 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800386 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
387
Colin Cross1661aff2021-03-12 17:56:51 -0800388 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700389 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800390 FlagWithInput("--project ", lintPaths.projectXML).
391 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700392 FlagWithOutput("--html ", html).
393 FlagWithOutput("--text ", text).
394 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700395 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
396 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
397 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
398 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
399 Flag("--exitcode").
400 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800401 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700402 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700403
Colin Cross1661aff2021-03-12 17:56:51 -0800404 rule.Temporary(lintPaths.projectXML)
405 rule.Temporary(lintPaths.configXML)
406
Colin Cross988dfcc2020-07-16 17:32:17 -0700407 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
408 cmd.FlagWithArg("--check ", checkOnly)
409 }
410
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700411 lintBaseline := l.getBaselineFilepath(ctx)
412 if lintBaseline.Valid() {
413 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000414 }
415
Colin Cross31972dc2021-03-04 10:44:12 -0800416 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700417
Colin Cross31972dc2021-03-04 10:44:12 -0800418 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700419
Colin Crossee4a8b72021-04-05 18:38:05 -0700420 // The HTML output contains a date, remove it to make the output deterministic.
421 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
422
Colin Crossf1a035e2020-11-16 17:32:30 -0800423 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700424
Colin Crossc0efd1d2020-07-03 11:56:24 -0700425 l.outputs = lintOutputs{
426 html: html,
427 text: text,
428 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700429
Colin Cross08dca382020-07-21 20:31:17 -0700430 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700431 }
Colin Cross014489c2020-06-02 20:09:13 -0700432
Colin Crossc0efd1d2020-07-03 11:56:24 -0700433 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700434 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700435 }
436}
Colin Cross014489c2020-06-02 20:09:13 -0700437
Colin Cross08dca382020-07-21 20:31:17 -0700438func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
439 htmlList := depSets.HTML.ToSortedList()
440 textList := depSets.Text.ToSortedList()
441 xmlList := depSets.XML.ToSortedList()
442
443 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
444 return nil
445 }
446
447 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
448 lintZip(ctx, htmlList, htmlZip)
449
450 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
451 lintZip(ctx, textList, textZip)
452
453 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
454 lintZip(ctx, xmlList, xmlZip)
455
456 return android.Paths{htmlZip, textZip, xmlZip}
457}
458
Colin Cross014489c2020-06-02 20:09:13 -0700459type lintSingleton struct {
460 htmlZip android.WritablePath
461 textZip android.WritablePath
462 xmlZip android.WritablePath
463}
464
465func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
466 l.generateLintReportZips(ctx)
467 l.copyLintDependencies(ctx)
468}
469
470func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900471 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700472 return
473 }
474
475 var frameworkDocStubs android.Module
476 ctx.VisitAllModules(func(m android.Module) {
477 if ctx.ModuleName(m) == "framework-doc-stubs" {
478 if frameworkDocStubs == nil {
479 frameworkDocStubs = m
480 } else {
481 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
482 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
483 }
484 }
485 })
486
487 if frameworkDocStubs == nil {
488 if !ctx.Config().AllowMissingDependencies() {
489 ctx.Errorf("lint: missing framework-doc-stubs")
490 }
491 return
492 }
493
494 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800495 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700496 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700497 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700498 })
499
500 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800501 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700502 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700503 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700504 })
505}
506
Colin Cross8a6ed372020-07-06 11:45:51 -0700507func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700508 return android.PathForOutput(ctx, "lint", "annotations.zip")
509}
510
Colin Cross8a6ed372020-07-06 11:45:51 -0700511func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700512 return android.PathForOutput(ctx, "lint", "api_versions.xml")
513}
514
515func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700516 if ctx.Config().UnbundledBuild() {
517 return
518 }
519
Colin Cross014489c2020-06-02 20:09:13 -0700520 var outputs []*lintOutputs
521 var dirs []string
522 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500523 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700524 return
525 }
526
Colin Cross56a83212020-09-15 18:30:11 -0700527 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
528 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
529 if apexInfo.IsForPlatform() {
530 // There are stray platform variants of modules in apexes that are not available for
531 // the platform, and they sometimes can't be built. Don't depend on them.
532 return
533 }
Colin Cross014489c2020-06-02 20:09:13 -0700534 }
535
Colin Cross08dca382020-07-21 20:31:17 -0700536 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700537 outputs = append(outputs, l.lintOutputs())
538 }
539 })
540
541 dirs = android.SortedUniqueStrings(dirs)
542
543 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
544 var paths android.Paths
545
546 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700547 if p := get(output); p != nil {
548 paths = append(paths, p)
549 }
Colin Cross014489c2020-06-02 20:09:13 -0700550 }
551
Colin Crossc0efd1d2020-07-03 11:56:24 -0700552 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700553 }
554
555 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
556 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
557
558 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
559 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
560
561 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
562 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
563
564 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
565}
566
567func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700568 if !ctx.Config().UnbundledBuild() {
569 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
570 }
Colin Cross014489c2020-06-02 20:09:13 -0700571}
572
573var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
574
575func init() {
576 android.RegisterSingletonType("lint",
577 func() android.Singleton { return &lintSingleton{} })
578}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700579
580func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
581 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
582
583 sort.Slice(paths, func(i, j int) bool {
584 return paths[i].String() < paths[j].String()
585 })
586
Colin Crossf1a035e2020-11-16 17:32:30 -0800587 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700588
Colin Crossf1a035e2020-11-16 17:32:30 -0800589 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700590 FlagWithOutput("-o ", outputPath).
591 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800592 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700593
Colin Crossf1a035e2020-11-16 17:32:30 -0800594 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700595}