blob: 12e412988a14294a966da23f1ff6b55129fa390d [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 Cross014489c2020-06-02 20:09:13 -0700316
Colin Cross8a6ed372020-07-06 11:45:51 -0700317 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900318 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700319 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
320 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
321 } else {
322 annotationsZipPath = copiedAnnotationsZipPath(ctx)
323 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
324 }
325
Colin Cross988dfcc2020-07-16 17:32:17 -0700326 cmd := rule.Command().
Colin Cross014489c2020-06-02 20:09:13 -0700327 Text("(").
Colin Crosse2221792020-07-13 13:23:00 -0700328 Flag("JAVA_OPTS=-Xmx3072m").
Colin Cross977b6a82020-06-23 10:22:49 -0700329 FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700330 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
331 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath).
Colin Cross84f3dc12021-03-04 09:56:15 -0800332 BuiltTool("lint").
Colin Cross014489c2020-06-02 20:09:13 -0700333 Flag("--quiet").
334 FlagWithInput("--project ", projectXML).
335 FlagWithInput("--config ", lintXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700336 FlagWithOutput("--html ", html).
337 FlagWithOutput("--text ", text).
338 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700339 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
340 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
341 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
342 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
343 Flag("--exitcode").
344 Flags(l.properties.Lint.Flags).
Colin Cross988dfcc2020-07-16 17:32:17 -0700345 Implicits(deps)
346
347 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
348 cmd.FlagWithArg("--check ", checkOnly)
349 }
350
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000351 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
352 var lintBaseline android.OptionalPath
353 if String(l.properties.Lint.Baseline_filename) != "" {
354 // if manually specified, we require the file to exist
355 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
356 } else {
357 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
358 }
359 if lintBaseline.Valid() {
360 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
361 }
362 }
363
Colin Cross988dfcc2020-07-16 17:32:17 -0700364 cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")")
Colin Cross014489c2020-06-02 20:09:13 -0700365
Colin Cross977b6a82020-06-23 10:22:49 -0700366 rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700367
Colin Crossf1a035e2020-11-16 17:32:30 -0800368 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700369
Colin Crossc0efd1d2020-07-03 11:56:24 -0700370 l.outputs = lintOutputs{
371 html: html,
372 text: text,
373 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700374
Colin Cross08dca382020-07-21 20:31:17 -0700375 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700376 }
Colin Cross014489c2020-06-02 20:09:13 -0700377
Colin Crossc0efd1d2020-07-03 11:56:24 -0700378 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700379 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700380 }
381}
Colin Cross014489c2020-06-02 20:09:13 -0700382
Colin Cross08dca382020-07-21 20:31:17 -0700383func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
384 htmlList := depSets.HTML.ToSortedList()
385 textList := depSets.Text.ToSortedList()
386 xmlList := depSets.XML.ToSortedList()
387
388 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
389 return nil
390 }
391
392 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
393 lintZip(ctx, htmlList, htmlZip)
394
395 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
396 lintZip(ctx, textList, textZip)
397
398 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
399 lintZip(ctx, xmlList, xmlZip)
400
401 return android.Paths{htmlZip, textZip, xmlZip}
402}
403
Colin Cross014489c2020-06-02 20:09:13 -0700404type lintSingleton struct {
405 htmlZip android.WritablePath
406 textZip android.WritablePath
407 xmlZip android.WritablePath
408}
409
410func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
411 l.generateLintReportZips(ctx)
412 l.copyLintDependencies(ctx)
413}
414
415func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900416 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700417 return
418 }
419
420 var frameworkDocStubs android.Module
421 ctx.VisitAllModules(func(m android.Module) {
422 if ctx.ModuleName(m) == "framework-doc-stubs" {
423 if frameworkDocStubs == nil {
424 frameworkDocStubs = m
425 } else {
426 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
427 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
428 }
429 }
430 })
431
432 if frameworkDocStubs == nil {
433 if !ctx.Config().AllowMissingDependencies() {
434 ctx.Errorf("lint: missing framework-doc-stubs")
435 }
436 return
437 }
438
439 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800440 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700441 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700442 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700443 })
444
445 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800446 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700447 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700448 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700449 })
450}
451
Colin Cross8a6ed372020-07-06 11:45:51 -0700452func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700453 return android.PathForOutput(ctx, "lint", "annotations.zip")
454}
455
Colin Cross8a6ed372020-07-06 11:45:51 -0700456func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700457 return android.PathForOutput(ctx, "lint", "api_versions.xml")
458}
459
460func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700461 if ctx.Config().UnbundledBuild() {
462 return
463 }
464
Colin Cross014489c2020-06-02 20:09:13 -0700465 var outputs []*lintOutputs
466 var dirs []string
467 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500468 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700469 return
470 }
471
Colin Cross56a83212020-09-15 18:30:11 -0700472 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
473 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
474 if apexInfo.IsForPlatform() {
475 // There are stray platform variants of modules in apexes that are not available for
476 // the platform, and they sometimes can't be built. Don't depend on them.
477 return
478 }
Colin Cross014489c2020-06-02 20:09:13 -0700479 }
480
Colin Cross08dca382020-07-21 20:31:17 -0700481 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700482 outputs = append(outputs, l.lintOutputs())
483 }
484 })
485
486 dirs = android.SortedUniqueStrings(dirs)
487
488 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
489 var paths android.Paths
490
491 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700492 if p := get(output); p != nil {
493 paths = append(paths, p)
494 }
Colin Cross014489c2020-06-02 20:09:13 -0700495 }
496
Colin Crossc0efd1d2020-07-03 11:56:24 -0700497 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700498 }
499
500 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
501 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
502
503 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
504 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
505
506 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
507 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
508
509 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
510}
511
512func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700513 if !ctx.Config().UnbundledBuild() {
514 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
515 }
Colin Cross014489c2020-06-02 20:09:13 -0700516}
517
518var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
519
520func init() {
521 android.RegisterSingletonType("lint",
522 func() android.Singleton { return &lintSingleton{} })
523}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700524
525func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
526 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
527
528 sort.Slice(paths, func(i, j int) bool {
529 return paths[i].String() < paths[j].String()
530 })
531
Colin Crossf1a035e2020-11-16 17:32:30 -0800532 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700533
Colin Crossf1a035e2020-11-16 17:32:30 -0800534 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700535 FlagWithOutput("-o ", outputPath).
536 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross053fca12020-08-19 13:51:47 -0700537 FlagWithRspFileInputList("-r ", paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700538
Colin Crossf1a035e2020-11-16 17:32:30 -0800539 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700540}