blob: 50b84dc71f272a398fb9142c060a111de9763a60 [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"
25)
26
27type LintProperties struct {
28 // Controls for running Android Lint on the module.
29 Lint struct {
30
31 // If true, run Android Lint on the module. Defaults to true.
32 Enabled *bool
33
34 // Flags to pass to the Android Lint tool.
35 Flags []string
36
37 // Checks that should be treated as fatal.
38 Fatal_checks []string
39
40 // Checks that should be treated as errors.
41 Error_checks []string
42
43 // Checks that should be treated as warnings.
44 Warning_checks []string
45
46 // Checks that should be skipped.
47 Disabled_checks []string
Colin Cross92e4b462020-06-18 15:56:48 -070048
49 // Modules that provide extra lint checks
50 Extra_check_modules []string
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000051
52 // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
53 Baseline_filename *string
Colin Cross014489c2020-06-02 20:09:13 -070054 }
55}
56
57type linter struct {
58 name string
59 manifest android.Path
60 mergedManifest android.Path
61 srcs android.Paths
62 srcJars android.Paths
63 resources android.Paths
64 classpath android.Paths
65 classes android.Path
66 extraLintCheckJars android.Paths
67 test bool
68 library bool
69 minSdkVersion string
70 targetSdkVersion string
71 compileSdkVersion string
72 javaLanguageLevel string
73 kotlinLanguageLevel string
74 outputs lintOutputs
75 properties LintProperties
Colin Crossc0efd1d2020-07-03 11:56:24 -070076
Colin Cross08dca382020-07-21 20:31:17 -070077 reports android.Paths
78
Colin Crossc0efd1d2020-07-03 11:56:24 -070079 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070080}
81
82type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070083 html android.Path
84 text android.Path
85 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070086
Colin Cross08dca382020-07-21 20:31:17 -070087 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -070088}
89
Colin Cross08dca382020-07-21 20:31:17 -070090type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -070091 lintOutputs() *lintOutputs
92}
93
Colin Cross08dca382020-07-21 20:31:17 -070094type lintDepSetsIntf interface {
95 LintDepSets() LintDepSets
96}
97
98type LintDepSets struct {
99 HTML, Text, XML *android.DepSet
100}
101
102type LintDepSetsBuilder struct {
103 HTML, Text, XML *android.DepSetBuilder
104}
105
106func NewLintDepSetBuilder() LintDepSetsBuilder {
107 return LintDepSetsBuilder{
108 HTML: android.NewDepSetBuilder(android.POSTORDER),
109 Text: android.NewDepSetBuilder(android.POSTORDER),
110 XML: android.NewDepSetBuilder(android.POSTORDER),
111 }
112}
113
114func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
115 l.HTML.Direct(html)
116 l.Text.Direct(text)
117 l.XML.Direct(xml)
118 return l
119}
120
121func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
122 if depSets.HTML != nil {
123 l.HTML.Transitive(depSets.HTML)
124 }
125 if depSets.Text != nil {
126 l.Text.Transitive(depSets.Text)
127 }
128 if depSets.XML != nil {
129 l.XML.Transitive(depSets.XML)
130 }
131 return l
132}
133
134func (l LintDepSetsBuilder) Build() LintDepSets {
135 return LintDepSets{
136 HTML: l.HTML.Build(),
137 Text: l.Text.Build(),
138 XML: l.XML.Build(),
139 }
140}
141
142func (l *linter) LintDepSets() LintDepSets {
143 return l.outputs.depSets
144}
145
146var _ lintDepSetsIntf = (*linter)(nil)
147
148var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700149
150func (l *linter) lintOutputs() *lintOutputs {
151 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700152}
153
154func (l *linter) enabled() bool {
155 return BoolDefault(l.properties.Lint.Enabled, true)
156}
157
Colin Cross92e4b462020-06-18 15:56:48 -0700158func (l *linter) deps(ctx android.BottomUpMutatorContext) {
159 if !l.enabled() {
160 return
161 }
162
Colin Cross988dfcc2020-07-16 17:32:17 -0700163 extraCheckModules := l.properties.Lint.Extra_check_modules
164
165 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
166 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
167 extraCheckModules = strings.Split(checkOnlyModules, ",")
168 }
169 }
170
171 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
172 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700173}
174
Colin Cross014489c2020-06-02 20:09:13 -0700175func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
Colin Cross977b6a82020-06-23 10:22:49 -0700176 rule *android.RuleBuilder) (projectXMLPath, configXMLPath, cacheDir, homeDir android.WritablePath, deps android.Paths) {
Colin Cross014489c2020-06-02 20:09:13 -0700177
178 var resourcesList android.WritablePath
179 if len(l.resources) > 0 {
180 // The list of resources may be too long to put on the command line, but
181 // we can't use the rsp file because it is already being used for srcs.
182 // Insert a second rule to write out the list of resources to a file.
183 resourcesList = android.PathForModuleOut(ctx, "lint", "resources.list")
Colin Crossf1a035e2020-11-16 17:32:30 -0800184 resListRule := android.NewRuleBuilder(pctx, ctx)
Colin Cross014489c2020-06-02 20:09:13 -0700185 resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList)
Colin Crossf1a035e2020-11-16 17:32:30 -0800186 resListRule.Build("lint_resources_list", "lint resources list")
Colin Cross014489c2020-06-02 20:09:13 -0700187 deps = append(deps, l.resources...)
188 }
189
190 projectXMLPath = android.PathForModuleOut(ctx, "lint", "project.xml")
191 // Lint looks for a lint.xml file next to the project.xml file, give it one.
192 configXMLPath = android.PathForModuleOut(ctx, "lint", "lint.xml")
193 cacheDir = android.PathForModuleOut(ctx, "lint", "cache")
Colin Cross977b6a82020-06-23 10:22:49 -0700194 homeDir = android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700195
196 srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars")
197 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
198
199 cmd := rule.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800200 BuiltTool("lint-project-xml").
Colin Cross014489c2020-06-02 20:09:13 -0700201 FlagWithOutput("--project_out ", projectXMLPath).
202 FlagWithOutput("--config_out ", configXMLPath).
203 FlagWithArg("--name ", ctx.ModuleName())
204
205 if l.library {
206 cmd.Flag("--library")
207 }
208 if l.test {
209 cmd.Flag("--test")
210 }
211 if l.manifest != nil {
212 deps = append(deps, l.manifest)
213 cmd.FlagWithArg("--manifest ", l.manifest.String())
214 }
215 if l.mergedManifest != nil {
216 deps = append(deps, l.mergedManifest)
217 cmd.FlagWithArg("--merged_manifest ", l.mergedManifest.String())
218 }
219
220 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
221 // lint separately.
222 cmd.FlagWithRspFileInputList("--srcs ", l.srcs)
223 deps = append(deps, l.srcs...)
224
225 cmd.FlagWithInput("--generated_srcs ", srcJarList)
226 deps = append(deps, l.srcJars...)
227
228 if resourcesList != nil {
229 cmd.FlagWithInput("--resources ", resourcesList)
230 }
231
232 if l.classes != nil {
233 deps = append(deps, l.classes)
234 cmd.FlagWithArg("--classes ", l.classes.String())
235 }
236
237 cmd.FlagForEachArg("--classpath ", l.classpath.Strings())
238 deps = append(deps, l.classpath...)
239
240 cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
241 deps = append(deps, l.extraLintCheckJars...)
242
Colin Crossc31efeb2020-06-23 10:25:26 -0700243 cmd.FlagWithArg("--root_dir ", "$PWD")
244
245 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
246 // the root dir is not set.
247 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700248
249 cmd.FlagWithInput("@",
250 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
251
252 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
253 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
254 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
255 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
256
Colin Cross977b6a82020-06-23 10:22:49 -0700257 return projectXMLPath, configXMLPath, cacheDir, homeDir, deps
Colin Cross014489c2020-06-02 20:09:13 -0700258}
259
Liz Kammer20ebfb42020-07-28 11:32:07 -0700260// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700261// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
262func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
263 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
264
265 rule.Command().Text("(").
266 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
267 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
268 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
269 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
270 l.minSdkVersion, l.targetSdkVersion).
271 Text(`echo "</manifest>"`).
272 Text(") >").Output(manifestPath)
273
274 return manifestPath
275}
276
277func (l *linter) lint(ctx android.ModuleContext) {
278 if !l.enabled() {
279 return
280 }
281
Colin Cross92e4b462020-06-18 15:56:48 -0700282 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
283 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800284 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
285 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
286 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700287 } else {
288 ctx.PropertyErrorf("lint.extra_check_modules",
289 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
290 }
291 }
292
Colin Crossf1a035e2020-11-16 17:32:30 -0800293 rule := android.NewRuleBuilder(pctx, ctx)
Colin Cross014489c2020-06-02 20:09:13 -0700294
295 if l.manifest == nil {
296 manifest := l.generateManifest(ctx, rule)
297 l.manifest = manifest
298 }
299
Colin Cross977b6a82020-06-23 10:22:49 -0700300 projectXML, lintXML, cacheDir, homeDir, deps := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700301
Colin Crossc0efd1d2020-07-03 11:56:24 -0700302 html := android.PathForModuleOut(ctx, "lint-report.html")
303 text := android.PathForModuleOut(ctx, "lint-report.txt")
304 xml := android.PathForModuleOut(ctx, "lint-report.xml")
305
Colin Cross08dca382020-07-21 20:31:17 -0700306 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700307
308 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700309 if depLint, ok := dep.(lintDepSetsIntf); ok {
310 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700311 }
312 })
Colin Cross014489c2020-06-02 20:09:13 -0700313
Colin Cross977b6a82020-06-23 10:22:49 -0700314 rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
315 rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800316 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700317
Colin Cross8a6ed372020-07-06 11:45:51 -0700318 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900319 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700320 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
321 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
322 } else {
323 annotationsZipPath = copiedAnnotationsZipPath(ctx)
324 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
325 }
326
Colin Cross988dfcc2020-07-16 17:32:17 -0700327 cmd := rule.Command().
Colin Cross014489c2020-06-02 20:09:13 -0700328 Text("(").
Colin Crosse2221792020-07-13 13:23:00 -0700329 Flag("JAVA_OPTS=-Xmx3072m").
Colin Cross977b6a82020-06-23 10:22:49 -0700330 FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700331 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
332 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath).
Colin Cross84f3dc12021-03-04 09:56:15 -0800333 BuiltTool("lint").
Colin Cross014489c2020-06-02 20:09:13 -0700334 Flag("--quiet").
335 FlagWithInput("--project ", projectXML).
336 FlagWithInput("--config ", lintXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700337 FlagWithOutput("--html ", html).
338 FlagWithOutput("--text ", text).
339 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700340 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
341 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
342 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
343 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
344 Flag("--exitcode").
345 Flags(l.properties.Lint.Flags).
Colin Cross988dfcc2020-07-16 17:32:17 -0700346 Implicits(deps)
347
348 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
349 cmd.FlagWithArg("--check ", checkOnly)
350 }
351
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000352 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
353 var lintBaseline android.OptionalPath
354 if String(l.properties.Lint.Baseline_filename) != "" {
355 // if manually specified, we require the file to exist
356 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
357 } else {
358 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
359 }
360 if lintBaseline.Valid() {
361 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
362 }
363 }
364
Colin Cross5c113d12021-03-04 10:01:34 -0800365 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)").Text(")")
Colin Cross014489c2020-06-02 20:09:13 -0700366
Colin Cross977b6a82020-06-23 10:22:49 -0700367 rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700368
Colin Crossf1a035e2020-11-16 17:32:30 -0800369 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700370
Colin Crossc0efd1d2020-07-03 11:56:24 -0700371 l.outputs = lintOutputs{
372 html: html,
373 text: text,
374 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700375
Colin Cross08dca382020-07-21 20:31:17 -0700376 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700377 }
Colin Cross014489c2020-06-02 20:09:13 -0700378
Colin Crossc0efd1d2020-07-03 11:56:24 -0700379 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700380 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700381 }
382}
Colin Cross014489c2020-06-02 20:09:13 -0700383
Colin Cross08dca382020-07-21 20:31:17 -0700384func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
385 htmlList := depSets.HTML.ToSortedList()
386 textList := depSets.Text.ToSortedList()
387 xmlList := depSets.XML.ToSortedList()
388
389 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
390 return nil
391 }
392
393 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
394 lintZip(ctx, htmlList, htmlZip)
395
396 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
397 lintZip(ctx, textList, textZip)
398
399 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
400 lintZip(ctx, xmlList, xmlZip)
401
402 return android.Paths{htmlZip, textZip, xmlZip}
403}
404
Colin Cross014489c2020-06-02 20:09:13 -0700405type lintSingleton struct {
406 htmlZip android.WritablePath
407 textZip android.WritablePath
408 xmlZip android.WritablePath
409}
410
411func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
412 l.generateLintReportZips(ctx)
413 l.copyLintDependencies(ctx)
414}
415
416func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900417 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700418 return
419 }
420
421 var frameworkDocStubs android.Module
422 ctx.VisitAllModules(func(m android.Module) {
423 if ctx.ModuleName(m) == "framework-doc-stubs" {
424 if frameworkDocStubs == nil {
425 frameworkDocStubs = m
426 } else {
427 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
428 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
429 }
430 }
431 })
432
433 if frameworkDocStubs == nil {
434 if !ctx.Config().AllowMissingDependencies() {
435 ctx.Errorf("lint: missing framework-doc-stubs")
436 }
437 return
438 }
439
440 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800441 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700442 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700443 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700444 })
445
446 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800447 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700448 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700449 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700450 })
451}
452
Colin Cross8a6ed372020-07-06 11:45:51 -0700453func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700454 return android.PathForOutput(ctx, "lint", "annotations.zip")
455}
456
Colin Cross8a6ed372020-07-06 11:45:51 -0700457func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700458 return android.PathForOutput(ctx, "lint", "api_versions.xml")
459}
460
461func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700462 if ctx.Config().UnbundledBuild() {
463 return
464 }
465
Colin Cross014489c2020-06-02 20:09:13 -0700466 var outputs []*lintOutputs
467 var dirs []string
468 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500469 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700470 return
471 }
472
Colin Cross56a83212020-09-15 18:30:11 -0700473 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
474 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
475 if apexInfo.IsForPlatform() {
476 // There are stray platform variants of modules in apexes that are not available for
477 // the platform, and they sometimes can't be built. Don't depend on them.
478 return
479 }
Colin Cross014489c2020-06-02 20:09:13 -0700480 }
481
Colin Cross08dca382020-07-21 20:31:17 -0700482 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700483 outputs = append(outputs, l.lintOutputs())
484 }
485 })
486
487 dirs = android.SortedUniqueStrings(dirs)
488
489 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
490 var paths android.Paths
491
492 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700493 if p := get(output); p != nil {
494 paths = append(paths, p)
495 }
Colin Cross014489c2020-06-02 20:09:13 -0700496 }
497
Colin Crossc0efd1d2020-07-03 11:56:24 -0700498 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700499 }
500
501 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
502 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
503
504 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
505 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
506
507 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
508 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
509
510 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
511}
512
513func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700514 if !ctx.Config().UnbundledBuild() {
515 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
516 }
Colin Cross014489c2020-06-02 20:09:13 -0700517}
518
519var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
520
521func init() {
522 android.RegisterSingletonType("lint",
523 func() android.Singleton { return &lintSingleton{} })
524}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700525
526func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
527 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
528
529 sort.Slice(paths, func(i, j int) bool {
530 return paths[i].String() < paths[j].String()
531 })
532
Colin Crossf1a035e2020-11-16 17:32:30 -0800533 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700534
Colin Crossf1a035e2020-11-16 17:32:30 -0800535 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700536 FlagWithOutput("-o ", outputPath).
537 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross053fca12020-08-19 13:51:47 -0700538 FlagWithRspFileInputList("-r ", paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700539
Colin Crossf1a035e2020-11-16 17:32:30 -0800540 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700541}