blob: a91278a901068f32e00b8cbc53bdd0ef3ae81ce2 [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
29type LintProperties struct {
30 // Controls for running Android Lint on the module.
31 Lint struct {
32
33 // If true, run Android Lint on the module. Defaults to true.
34 Enabled *bool
35
36 // Flags to pass to the Android Lint tool.
37 Flags []string
38
39 // Checks that should be treated as fatal.
40 Fatal_checks []string
41
42 // Checks that should be treated as errors.
43 Error_checks []string
44
45 // Checks that should be treated as warnings.
46 Warning_checks []string
47
48 // Checks that should be skipped.
49 Disabled_checks []string
Colin Cross92e4b462020-06-18 15:56:48 -070050
51 // Modules that provide extra lint checks
52 Extra_check_modules []string
Pedro Loureiro5d190cc2021-02-15 15:41:33 +000053
54 // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
55 Baseline_filename *string
Colin Cross014489c2020-06-02 20:09:13 -070056 }
57}
58
59type linter struct {
60 name string
61 manifest android.Path
62 mergedManifest android.Path
63 srcs android.Paths
64 srcJars android.Paths
65 resources android.Paths
66 classpath android.Paths
67 classes android.Path
68 extraLintCheckJars android.Paths
69 test bool
70 library bool
71 minSdkVersion string
72 targetSdkVersion string
73 compileSdkVersion string
74 javaLanguageLevel string
75 kotlinLanguageLevel string
76 outputs lintOutputs
77 properties LintProperties
Colin Crossc0efd1d2020-07-03 11:56:24 -070078
Colin Cross08dca382020-07-21 20:31:17 -070079 reports android.Paths
80
Colin Crossc0efd1d2020-07-03 11:56:24 -070081 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070082}
83
84type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070085 html android.Path
86 text android.Path
87 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070088
Colin Cross08dca382020-07-21 20:31:17 -070089 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -070090}
91
Colin Cross08dca382020-07-21 20:31:17 -070092type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -070093 lintOutputs() *lintOutputs
94}
95
Colin Cross08dca382020-07-21 20:31:17 -070096type lintDepSetsIntf interface {
97 LintDepSets() LintDepSets
98}
99
100type LintDepSets struct {
101 HTML, Text, XML *android.DepSet
102}
103
104type LintDepSetsBuilder struct {
105 HTML, Text, XML *android.DepSetBuilder
106}
107
108func NewLintDepSetBuilder() LintDepSetsBuilder {
109 return LintDepSetsBuilder{
110 HTML: android.NewDepSetBuilder(android.POSTORDER),
111 Text: android.NewDepSetBuilder(android.POSTORDER),
112 XML: android.NewDepSetBuilder(android.POSTORDER),
113 }
114}
115
116func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
117 l.HTML.Direct(html)
118 l.Text.Direct(text)
119 l.XML.Direct(xml)
120 return l
121}
122
123func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
124 if depSets.HTML != nil {
125 l.HTML.Transitive(depSets.HTML)
126 }
127 if depSets.Text != nil {
128 l.Text.Transitive(depSets.Text)
129 }
130 if depSets.XML != nil {
131 l.XML.Transitive(depSets.XML)
132 }
133 return l
134}
135
136func (l LintDepSetsBuilder) Build() LintDepSets {
137 return LintDepSets{
138 HTML: l.HTML.Build(),
139 Text: l.Text.Build(),
140 XML: l.XML.Build(),
141 }
142}
143
144func (l *linter) LintDepSets() LintDepSets {
145 return l.outputs.depSets
146}
147
148var _ lintDepSetsIntf = (*linter)(nil)
149
150var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700151
152func (l *linter) lintOutputs() *lintOutputs {
153 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700154}
155
156func (l *linter) enabled() bool {
157 return BoolDefault(l.properties.Lint.Enabled, true)
158}
159
Colin Cross92e4b462020-06-18 15:56:48 -0700160func (l *linter) deps(ctx android.BottomUpMutatorContext) {
161 if !l.enabled() {
162 return
163 }
164
Colin Cross988dfcc2020-07-16 17:32:17 -0700165 extraCheckModules := l.properties.Lint.Extra_check_modules
166
167 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
168 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
169 extraCheckModules = strings.Split(checkOnlyModules, ",")
170 }
171 }
172
173 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
174 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700175}
176
Colin Crossad22bc22021-03-10 09:45:40 -0800177// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
178// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800179type lintPaths struct {
180 projectXML android.WritablePath
181 configXML android.WritablePath
182 cacheDir android.WritablePath
183 homeDir android.WritablePath
184 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800185}
186
Colin Cross9b93af42021-03-10 10:40:58 -0800187func lintRBEExecStrategy(ctx android.ModuleContext) string {
188 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
189}
190
Colin Cross31972dc2021-03-04 10:44:12 -0800191func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800192 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700193 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800194 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
195 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
196 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700197
Colin Cross1661aff2021-03-12 17:56:51 -0800198 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700199 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
200
201 cmd := rule.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800202 BuiltTool("lint-project-xml").
Colin Cross014489c2020-06-02 20:09:13 -0700203 FlagWithOutput("--project_out ", projectXMLPath).
204 FlagWithOutput("--config_out ", configXMLPath).
205 FlagWithArg("--name ", ctx.ModuleName())
206
207 if l.library {
208 cmd.Flag("--library")
209 }
210 if l.test {
211 cmd.Flag("--test")
212 }
213 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700214 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700215 }
216 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700217 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700218 }
219
Colin Cross5bedfa22021-03-23 17:07:14 -0700220 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
221 // lint separately.
222 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
223 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
Colin Cross014489c2020-06-02 20:09:13 -0700224
225 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700226
Colin Cross5bedfa22021-03-23 17:07:14 -0700227 if len(l.resources) > 0 {
228 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
229 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700230 }
231
232 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700233 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700234 }
235
Colin Cross5bedfa22021-03-23 17:07:14 -0700236 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700237
Colin Cross5bedfa22021-03-23 17:07:14 -0700238 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700239
Colin Cross1661aff2021-03-12 17:56:51 -0800240 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700241
242 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
243 // the root dir is not set.
244 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700245
246 cmd.FlagWithInput("@",
247 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
248
249 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
250 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
251 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
252 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
253
Colin Cross31972dc2021-03-04 10:44:12 -0800254 return lintPaths{
255 projectXML: projectXMLPath,
256 configXML: configXMLPath,
257 cacheDir: cacheDir,
258 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800259 }
260
Colin Cross014489c2020-06-02 20:09:13 -0700261}
262
Liz Kammer20ebfb42020-07-28 11:32:07 -0700263// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700264// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800265func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700266 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
267
268 rule.Command().Text("(").
269 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
270 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
271 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
272 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
273 l.minSdkVersion, l.targetSdkVersion).
274 Text(`echo "</manifest>"`).
275 Text(") >").Output(manifestPath)
276
277 return manifestPath
278}
279
280func (l *linter) lint(ctx android.ModuleContext) {
281 if !l.enabled() {
282 return
283 }
284
Colin Cross92e4b462020-06-18 15:56:48 -0700285 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
286 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800287 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
288 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
289 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700290 } else {
291 ctx.PropertyErrorf("lint.extra_check_modules",
292 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
293 }
294 }
295
Colin Cross1661aff2021-03-12 17:56:51 -0800296 rule := android.NewRuleBuilder(pctx, ctx).
297 Sbox(android.PathForModuleOut(ctx, "lint"),
298 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
299 SandboxInputs()
300
301 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
302 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
303 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
304 rule.Rewrapper(&remoteexec.REParams{
305 Labels: map[string]string{"type": "tool", "name": "lint"},
306 ExecStrategy: lintRBEExecStrategy(ctx),
307 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
308 EnvironmentVariables: []string{
309 "LANG",
310 },
311 Platform: map[string]string{remoteexec.PoolKey: pool},
312 })
313 }
Colin Cross014489c2020-06-02 20:09:13 -0700314
315 if l.manifest == nil {
316 manifest := l.generateManifest(ctx, rule)
317 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800318 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700319 }
320
Colin Cross31972dc2021-03-04 10:44:12 -0800321 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700322
Colin Cross1661aff2021-03-12 17:56:51 -0800323 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
324 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
325 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700326
Colin Cross08dca382020-07-21 20:31:17 -0700327 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700328
329 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700330 if depLint, ok := dep.(lintDepSetsIntf); ok {
331 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700332 }
333 })
Colin Cross014489c2020-06-02 20:09:13 -0700334
Colin Cross31972dc2021-03-04 10:44:12 -0800335 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
336 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800337 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700338
Colin Cross8a6ed372020-07-06 11:45:51 -0700339 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900340 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700341 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
342 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
343 } else {
344 annotationsZipPath = copiedAnnotationsZipPath(ctx)
345 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
346 }
347
Colin Cross31972dc2021-03-04 10:44:12 -0800348 cmd := rule.Command()
349
350 cmd.Flag("JAVA_OPTS=-Xmx3072m").
351 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700352 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800353 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
354
Colin Cross1661aff2021-03-12 17:56:51 -0800355 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700356 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800357 FlagWithInput("--project ", lintPaths.projectXML).
358 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700359 FlagWithOutput("--html ", html).
360 FlagWithOutput("--text ", text).
361 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700362 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
363 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
364 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
365 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
366 Flag("--exitcode").
367 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800368 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700369 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700370
Colin Cross1661aff2021-03-12 17:56:51 -0800371 rule.Temporary(lintPaths.projectXML)
372 rule.Temporary(lintPaths.configXML)
373
Colin Cross988dfcc2020-07-16 17:32:17 -0700374 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
375 cmd.FlagWithArg("--check ", checkOnly)
376 }
377
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000378 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
379 var lintBaseline android.OptionalPath
380 if String(l.properties.Lint.Baseline_filename) != "" {
381 // if manually specified, we require the file to exist
382 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
383 } else {
384 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
385 }
386 if lintBaseline.Valid() {
387 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
388 }
389 }
390
Colin Cross31972dc2021-03-04 10:44:12 -0800391 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700392
Colin Cross31972dc2021-03-04 10:44:12 -0800393 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700394
Colin Crossee4a8b72021-04-05 18:38:05 -0700395 // The HTML output contains a date, remove it to make the output deterministic.
396 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
397
Colin Crossf1a035e2020-11-16 17:32:30 -0800398 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700399
Colin Crossc0efd1d2020-07-03 11:56:24 -0700400 l.outputs = lintOutputs{
401 html: html,
402 text: text,
403 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700404
Colin Cross08dca382020-07-21 20:31:17 -0700405 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700406 }
Colin Cross014489c2020-06-02 20:09:13 -0700407
Colin Crossc0efd1d2020-07-03 11:56:24 -0700408 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700409 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700410 }
411}
Colin Cross014489c2020-06-02 20:09:13 -0700412
Colin Cross08dca382020-07-21 20:31:17 -0700413func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
414 htmlList := depSets.HTML.ToSortedList()
415 textList := depSets.Text.ToSortedList()
416 xmlList := depSets.XML.ToSortedList()
417
418 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
419 return nil
420 }
421
422 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
423 lintZip(ctx, htmlList, htmlZip)
424
425 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
426 lintZip(ctx, textList, textZip)
427
428 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
429 lintZip(ctx, xmlList, xmlZip)
430
431 return android.Paths{htmlZip, textZip, xmlZip}
432}
433
Colin Cross014489c2020-06-02 20:09:13 -0700434type lintSingleton struct {
435 htmlZip android.WritablePath
436 textZip android.WritablePath
437 xmlZip android.WritablePath
438}
439
440func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
441 l.generateLintReportZips(ctx)
442 l.copyLintDependencies(ctx)
443}
444
445func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900446 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700447 return
448 }
449
450 var frameworkDocStubs android.Module
451 ctx.VisitAllModules(func(m android.Module) {
452 if ctx.ModuleName(m) == "framework-doc-stubs" {
453 if frameworkDocStubs == nil {
454 frameworkDocStubs = m
455 } else {
456 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
457 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
458 }
459 }
460 })
461
462 if frameworkDocStubs == nil {
463 if !ctx.Config().AllowMissingDependencies() {
464 ctx.Errorf("lint: missing framework-doc-stubs")
465 }
466 return
467 }
468
469 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800470 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700471 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700472 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700473 })
474
475 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800476 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700477 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700478 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700479 })
480}
481
Colin Cross8a6ed372020-07-06 11:45:51 -0700482func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700483 return android.PathForOutput(ctx, "lint", "annotations.zip")
484}
485
Colin Cross8a6ed372020-07-06 11:45:51 -0700486func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700487 return android.PathForOutput(ctx, "lint", "api_versions.xml")
488}
489
490func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700491 if ctx.Config().UnbundledBuild() {
492 return
493 }
494
Colin Cross014489c2020-06-02 20:09:13 -0700495 var outputs []*lintOutputs
496 var dirs []string
497 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500498 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700499 return
500 }
501
Colin Cross56a83212020-09-15 18:30:11 -0700502 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
503 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
504 if apexInfo.IsForPlatform() {
505 // There are stray platform variants of modules in apexes that are not available for
506 // the platform, and they sometimes can't be built. Don't depend on them.
507 return
508 }
Colin Cross014489c2020-06-02 20:09:13 -0700509 }
510
Colin Cross08dca382020-07-21 20:31:17 -0700511 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700512 outputs = append(outputs, l.lintOutputs())
513 }
514 })
515
516 dirs = android.SortedUniqueStrings(dirs)
517
518 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
519 var paths android.Paths
520
521 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700522 if p := get(output); p != nil {
523 paths = append(paths, p)
524 }
Colin Cross014489c2020-06-02 20:09:13 -0700525 }
526
Colin Crossc0efd1d2020-07-03 11:56:24 -0700527 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700528 }
529
530 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
531 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
532
533 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
534 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
535
536 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
537 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
538
539 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
540}
541
542func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700543 if !ctx.Config().UnbundledBuild() {
544 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
545 }
Colin Cross014489c2020-06-02 20:09:13 -0700546}
547
548var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
549
550func init() {
551 android.RegisterSingletonType("lint",
552 func() android.Singleton { return &lintSingleton{} })
553}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700554
555func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
556 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
557
558 sort.Slice(paths, func(i, j int) bool {
559 return paths[i].String() < paths[j].String()
560 })
561
Colin Crossf1a035e2020-11-16 17:32:30 -0800562 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700563
Colin Crossf1a035e2020-11-16 17:32:30 -0800564 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700565 FlagWithOutput("-o ", outputPath).
566 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800567 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700568
Colin Crossf1a035e2020-11-16 17:32:30 -0800569 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700570}