blob: a77daa85d833db2b0d3e5f3214e13aa19b7a6256 [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 {
Pedro Loureirof4a88b12021-02-25 16:23:22 +000060 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
78 extraMainlineLintErrors []string
Colin Crossc0efd1d2020-07-03 11:56:24 -070079
Colin Cross08dca382020-07-21 20:31:17 -070080 reports android.Paths
81
Colin Crossc0efd1d2020-07-03 11:56:24 -070082 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070083}
84
85type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070086 html android.Path
87 text android.Path
88 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070089
Colin Cross08dca382020-07-21 20:31:17 -070090 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -070091}
92
Colin Cross08dca382020-07-21 20:31:17 -070093type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -070094 lintOutputs() *lintOutputs
95}
96
Colin Cross08dca382020-07-21 20:31:17 -070097type lintDepSetsIntf interface {
98 LintDepSets() LintDepSets
99}
100
101type LintDepSets struct {
102 HTML, Text, XML *android.DepSet
103}
104
105type LintDepSetsBuilder struct {
106 HTML, Text, XML *android.DepSetBuilder
107}
108
109func NewLintDepSetBuilder() LintDepSetsBuilder {
110 return LintDepSetsBuilder{
111 HTML: android.NewDepSetBuilder(android.POSTORDER),
112 Text: android.NewDepSetBuilder(android.POSTORDER),
113 XML: android.NewDepSetBuilder(android.POSTORDER),
114 }
115}
116
117func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
118 l.HTML.Direct(html)
119 l.Text.Direct(text)
120 l.XML.Direct(xml)
121 return l
122}
123
124func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
125 if depSets.HTML != nil {
126 l.HTML.Transitive(depSets.HTML)
127 }
128 if depSets.Text != nil {
129 l.Text.Transitive(depSets.Text)
130 }
131 if depSets.XML != nil {
132 l.XML.Transitive(depSets.XML)
133 }
134 return l
135}
136
137func (l LintDepSetsBuilder) Build() LintDepSets {
138 return LintDepSets{
139 HTML: l.HTML.Build(),
140 Text: l.Text.Build(),
141 XML: l.XML.Build(),
142 }
143}
144
145func (l *linter) LintDepSets() LintDepSets {
146 return l.outputs.depSets
147}
148
149var _ lintDepSetsIntf = (*linter)(nil)
150
151var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700152
153func (l *linter) lintOutputs() *lintOutputs {
154 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700155}
156
157func (l *linter) enabled() bool {
158 return BoolDefault(l.properties.Lint.Enabled, true)
159}
160
Colin Cross92e4b462020-06-18 15:56:48 -0700161func (l *linter) deps(ctx android.BottomUpMutatorContext) {
162 if !l.enabled() {
163 return
164 }
165
Colin Cross988dfcc2020-07-16 17:32:17 -0700166 extraCheckModules := l.properties.Lint.Extra_check_modules
167
168 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
169 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
170 extraCheckModules = strings.Split(checkOnlyModules, ",")
171 }
172 }
173
174 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
175 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700176}
177
Colin Crossad22bc22021-03-10 09:45:40 -0800178// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
179// around.
Colin Cross31972dc2021-03-04 10:44:12 -0800180type lintPaths struct {
181 projectXML android.WritablePath
182 configXML android.WritablePath
183 cacheDir android.WritablePath
184 homeDir android.WritablePath
185 srcjarDir android.WritablePath
Colin Cross31972dc2021-03-04 10:44:12 -0800186}
187
Colin Cross9b93af42021-03-10 10:40:58 -0800188func lintRBEExecStrategy(ctx android.ModuleContext) string {
189 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
190}
191
Colin Cross31972dc2021-03-04 10:44:12 -0800192func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
Colin Cross31972dc2021-03-04 10:44:12 -0800193 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700194 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800195 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
196 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
197 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700198
Colin Cross1661aff2021-03-12 17:56:51 -0800199 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700200 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
201
202 cmd := rule.Command().
Jaewoong Jung5a420252021-04-19 17:58:22 -0700203 BuiltTool("lint_project_xml").
Colin Cross014489c2020-06-02 20:09:13 -0700204 FlagWithOutput("--project_out ", projectXMLPath).
205 FlagWithOutput("--config_out ", configXMLPath).
206 FlagWithArg("--name ", ctx.ModuleName())
207
208 if l.library {
209 cmd.Flag("--library")
210 }
211 if l.test {
212 cmd.Flag("--test")
213 }
214 if l.manifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700215 cmd.FlagWithInput("--manifest ", l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700216 }
217 if l.mergedManifest != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700218 cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700219 }
220
Colin Cross5bedfa22021-03-23 17:07:14 -0700221 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
222 // lint separately.
223 srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
224 cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
Colin Cross014489c2020-06-02 20:09:13 -0700225
226 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700227
Colin Cross5bedfa22021-03-23 17:07:14 -0700228 if len(l.resources) > 0 {
229 resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
230 cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
Colin Cross014489c2020-06-02 20:09:13 -0700231 }
232
233 if l.classes != nil {
Colin Cross5bedfa22021-03-23 17:07:14 -0700234 cmd.FlagWithInput("--classes ", l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700235 }
236
Colin Cross5bedfa22021-03-23 17:07:14 -0700237 cmd.FlagForEachInput("--classpath ", l.classpath)
Colin Cross014489c2020-06-02 20:09:13 -0700238
Colin Cross5bedfa22021-03-23 17:07:14 -0700239 cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
Colin Cross014489c2020-06-02 20:09:13 -0700240
Colin Cross1661aff2021-03-12 17:56:51 -0800241 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700242
243 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
244 // the root dir is not set.
245 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700246
247 cmd.FlagWithInput("@",
248 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
249
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000250 cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
Colin Cross014489c2020-06-02 20:09:13 -0700251 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
252 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
253 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
254 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
255
Colin Cross31972dc2021-03-04 10:44:12 -0800256 return lintPaths{
257 projectXML: projectXMLPath,
258 configXML: configXMLPath,
259 cacheDir: cacheDir,
260 homeDir: homeDir,
Colin Cross31972dc2021-03-04 10:44:12 -0800261 }
262
Colin Cross014489c2020-06-02 20:09:13 -0700263}
264
Liz Kammer20ebfb42020-07-28 11:32:07 -0700265// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700266// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800267func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700268 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
269
270 rule.Command().Text("(").
271 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
272 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
273 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
274 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
275 l.minSdkVersion, l.targetSdkVersion).
276 Text(`echo "</manifest>"`).
277 Text(") >").Output(manifestPath)
278
279 return manifestPath
280}
281
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700282func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
283 var lintBaseline android.OptionalPath
284 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
285 if String(l.properties.Lint.Baseline_filename) != "" {
286 // if manually specified, we require the file to exist
287 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
288 } else {
289 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
290 }
291 }
292 return lintBaseline
293}
294
Colin Cross014489c2020-06-02 20:09:13 -0700295func (l *linter) lint(ctx android.ModuleContext) {
296 if !l.enabled() {
297 return
298 }
299
Pedro Loureirof4a88b12021-02-25 16:23:22 +0000300 if l.minSdkVersion != l.compileSdkVersion {
301 l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, "NewApi")
302 }
303
Colin Cross92e4b462020-06-18 15:56:48 -0700304 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
305 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800306 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
307 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
308 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700309 } else {
310 ctx.PropertyErrorf("lint.extra_check_modules",
311 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
312 }
313 }
314
Colin Cross1661aff2021-03-12 17:56:51 -0800315 rule := android.NewRuleBuilder(pctx, ctx).
316 Sbox(android.PathForModuleOut(ctx, "lint"),
317 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
318 SandboxInputs()
319
320 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
321 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
322 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
323 rule.Rewrapper(&remoteexec.REParams{
324 Labels: map[string]string{"type": "tool", "name": "lint"},
325 ExecStrategy: lintRBEExecStrategy(ctx),
326 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
327 EnvironmentVariables: []string{
328 "LANG",
329 },
330 Platform: map[string]string{remoteexec.PoolKey: pool},
331 })
332 }
Colin Cross014489c2020-06-02 20:09:13 -0700333
334 if l.manifest == nil {
335 manifest := l.generateManifest(ctx, rule)
336 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800337 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700338 }
339
Colin Cross31972dc2021-03-04 10:44:12 -0800340 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700341
Colin Cross1661aff2021-03-12 17:56:51 -0800342 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
343 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
344 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700345
Colin Cross08dca382020-07-21 20:31:17 -0700346 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700347
348 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700349 if depLint, ok := dep.(lintDepSetsIntf); ok {
350 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700351 }
352 })
Colin Cross014489c2020-06-02 20:09:13 -0700353
Colin Cross31972dc2021-03-04 10:44:12 -0800354 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
355 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800356 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700357
Colin Cross8a6ed372020-07-06 11:45:51 -0700358 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900359 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700360 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
361 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
362 } else {
363 annotationsZipPath = copiedAnnotationsZipPath(ctx)
364 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
365 }
366
Colin Cross31972dc2021-03-04 10:44:12 -0800367 cmd := rule.Command()
368
Pedro Loureiro70acc3d2021-04-06 17:49:19 +0000369 cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
Colin Cross31972dc2021-03-04 10:44:12 -0800370 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700371 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800372 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
373
Colin Cross1661aff2021-03-12 17:56:51 -0800374 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700375 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800376 FlagWithInput("--project ", lintPaths.projectXML).
377 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700378 FlagWithOutput("--html ", html).
379 FlagWithOutput("--text ", text).
380 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700381 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
382 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
383 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
384 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
385 Flag("--exitcode").
386 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800387 Implicit(annotationsZipPath).
Colin Cross5bedfa22021-03-23 17:07:14 -0700388 Implicit(apiVersionsXMLPath)
Colin Cross988dfcc2020-07-16 17:32:17 -0700389
Colin Cross1661aff2021-03-12 17:56:51 -0800390 rule.Temporary(lintPaths.projectXML)
391 rule.Temporary(lintPaths.configXML)
392
Colin Cross988dfcc2020-07-16 17:32:17 -0700393 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
394 cmd.FlagWithArg("--check ", checkOnly)
395 }
396
Jaewoong Jung302c5b82021-04-19 08:54:36 -0700397 lintBaseline := l.getBaselineFilepath(ctx)
398 if lintBaseline.Valid() {
399 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000400 }
401
Colin Cross31972dc2021-03-04 10:44:12 -0800402 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700403
Colin Cross31972dc2021-03-04 10:44:12 -0800404 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700405
Colin Crossee4a8b72021-04-05 18:38:05 -0700406 // The HTML output contains a date, remove it to make the output deterministic.
407 rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
408
Colin Crossf1a035e2020-11-16 17:32:30 -0800409 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700410
Colin Crossc0efd1d2020-07-03 11:56:24 -0700411 l.outputs = lintOutputs{
412 html: html,
413 text: text,
414 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700415
Colin Cross08dca382020-07-21 20:31:17 -0700416 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700417 }
Colin Cross014489c2020-06-02 20:09:13 -0700418
Colin Crossc0efd1d2020-07-03 11:56:24 -0700419 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700420 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700421 }
422}
Colin Cross014489c2020-06-02 20:09:13 -0700423
Colin Cross08dca382020-07-21 20:31:17 -0700424func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
425 htmlList := depSets.HTML.ToSortedList()
426 textList := depSets.Text.ToSortedList()
427 xmlList := depSets.XML.ToSortedList()
428
429 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
430 return nil
431 }
432
433 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
434 lintZip(ctx, htmlList, htmlZip)
435
436 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
437 lintZip(ctx, textList, textZip)
438
439 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
440 lintZip(ctx, xmlList, xmlZip)
441
442 return android.Paths{htmlZip, textZip, xmlZip}
443}
444
Colin Cross014489c2020-06-02 20:09:13 -0700445type lintSingleton struct {
446 htmlZip android.WritablePath
447 textZip android.WritablePath
448 xmlZip android.WritablePath
449}
450
451func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
452 l.generateLintReportZips(ctx)
453 l.copyLintDependencies(ctx)
454}
455
456func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900457 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700458 return
459 }
460
461 var frameworkDocStubs android.Module
462 ctx.VisitAllModules(func(m android.Module) {
463 if ctx.ModuleName(m) == "framework-doc-stubs" {
464 if frameworkDocStubs == nil {
465 frameworkDocStubs = m
466 } else {
467 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
468 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
469 }
470 }
471 })
472
473 if frameworkDocStubs == nil {
474 if !ctx.Config().AllowMissingDependencies() {
475 ctx.Errorf("lint: missing framework-doc-stubs")
476 }
477 return
478 }
479
480 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800481 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700482 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700483 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700484 })
485
486 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800487 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700488 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700489 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700490 })
491}
492
Colin Cross8a6ed372020-07-06 11:45:51 -0700493func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700494 return android.PathForOutput(ctx, "lint", "annotations.zip")
495}
496
Colin Cross8a6ed372020-07-06 11:45:51 -0700497func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700498 return android.PathForOutput(ctx, "lint", "api_versions.xml")
499}
500
501func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700502 if ctx.Config().UnbundledBuild() {
503 return
504 }
505
Colin Cross014489c2020-06-02 20:09:13 -0700506 var outputs []*lintOutputs
507 var dirs []string
508 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500509 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700510 return
511 }
512
Colin Cross56a83212020-09-15 18:30:11 -0700513 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
514 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
515 if apexInfo.IsForPlatform() {
516 // There are stray platform variants of modules in apexes that are not available for
517 // the platform, and they sometimes can't be built. Don't depend on them.
518 return
519 }
Colin Cross014489c2020-06-02 20:09:13 -0700520 }
521
Colin Cross08dca382020-07-21 20:31:17 -0700522 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700523 outputs = append(outputs, l.lintOutputs())
524 }
525 })
526
527 dirs = android.SortedUniqueStrings(dirs)
528
529 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
530 var paths android.Paths
531
532 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700533 if p := get(output); p != nil {
534 paths = append(paths, p)
535 }
Colin Cross014489c2020-06-02 20:09:13 -0700536 }
537
Colin Crossc0efd1d2020-07-03 11:56:24 -0700538 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700539 }
540
541 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
542 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
543
544 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
545 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
546
547 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
548 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
549
550 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
551}
552
553func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700554 if !ctx.Config().UnbundledBuild() {
555 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
556 }
Colin Cross014489c2020-06-02 20:09:13 -0700557}
558
559var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
560
561func init() {
562 android.RegisterSingletonType("lint",
563 func() android.Singleton { return &lintSingleton{} })
564}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700565
566func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
567 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
568
569 sort.Slice(paths, func(i, j int) bool {
570 return paths[i].String() < paths[j].String()
571 })
572
Colin Crossf1a035e2020-11-16 17:32:30 -0800573 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700574
Colin Crossf1a035e2020-11-16 17:32:30 -0800575 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700576 FlagWithOutput("-o ", outputPath).
577 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800578 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700579
Colin Crossf1a035e2020-11-16 17:32:30 -0800580 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700581}