blob: 475e8dc7cf2eda418c5d619f74b34ddeca91bda2 [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 Crossf1a035e2020-11-16 17:32:30 -0800395 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700396
Colin Crossc0efd1d2020-07-03 11:56:24 -0700397 l.outputs = lintOutputs{
398 html: html,
399 text: text,
400 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700401
Colin Cross08dca382020-07-21 20:31:17 -0700402 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700403 }
Colin Cross014489c2020-06-02 20:09:13 -0700404
Colin Crossc0efd1d2020-07-03 11:56:24 -0700405 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700406 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700407 }
408}
Colin Cross014489c2020-06-02 20:09:13 -0700409
Colin Cross08dca382020-07-21 20:31:17 -0700410func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
411 htmlList := depSets.HTML.ToSortedList()
412 textList := depSets.Text.ToSortedList()
413 xmlList := depSets.XML.ToSortedList()
414
415 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
416 return nil
417 }
418
419 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
420 lintZip(ctx, htmlList, htmlZip)
421
422 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
423 lintZip(ctx, textList, textZip)
424
425 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
426 lintZip(ctx, xmlList, xmlZip)
427
428 return android.Paths{htmlZip, textZip, xmlZip}
429}
430
Colin Cross014489c2020-06-02 20:09:13 -0700431type lintSingleton struct {
432 htmlZip android.WritablePath
433 textZip android.WritablePath
434 xmlZip android.WritablePath
435}
436
437func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
438 l.generateLintReportZips(ctx)
439 l.copyLintDependencies(ctx)
440}
441
442func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900443 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700444 return
445 }
446
447 var frameworkDocStubs android.Module
448 ctx.VisitAllModules(func(m android.Module) {
449 if ctx.ModuleName(m) == "framework-doc-stubs" {
450 if frameworkDocStubs == nil {
451 frameworkDocStubs = m
452 } else {
453 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
454 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
455 }
456 }
457 })
458
459 if frameworkDocStubs == nil {
460 if !ctx.Config().AllowMissingDependencies() {
461 ctx.Errorf("lint: missing framework-doc-stubs")
462 }
463 return
464 }
465
466 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800467 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700468 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700469 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700470 })
471
472 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800473 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700474 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700475 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700476 })
477}
478
Colin Cross8a6ed372020-07-06 11:45:51 -0700479func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700480 return android.PathForOutput(ctx, "lint", "annotations.zip")
481}
482
Colin Cross8a6ed372020-07-06 11:45:51 -0700483func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700484 return android.PathForOutput(ctx, "lint", "api_versions.xml")
485}
486
487func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700488 if ctx.Config().UnbundledBuild() {
489 return
490 }
491
Colin Cross014489c2020-06-02 20:09:13 -0700492 var outputs []*lintOutputs
493 var dirs []string
494 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500495 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700496 return
497 }
498
Colin Cross56a83212020-09-15 18:30:11 -0700499 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
500 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
501 if apexInfo.IsForPlatform() {
502 // There are stray platform variants of modules in apexes that are not available for
503 // the platform, and they sometimes can't be built. Don't depend on them.
504 return
505 }
Colin Cross014489c2020-06-02 20:09:13 -0700506 }
507
Colin Cross08dca382020-07-21 20:31:17 -0700508 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700509 outputs = append(outputs, l.lintOutputs())
510 }
511 })
512
513 dirs = android.SortedUniqueStrings(dirs)
514
515 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
516 var paths android.Paths
517
518 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700519 if p := get(output); p != nil {
520 paths = append(paths, p)
521 }
Colin Cross014489c2020-06-02 20:09:13 -0700522 }
523
Colin Crossc0efd1d2020-07-03 11:56:24 -0700524 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700525 }
526
527 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
528 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
529
530 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
531 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
532
533 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
534 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
535
536 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
537}
538
539func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700540 if !ctx.Config().UnbundledBuild() {
541 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
542 }
Colin Cross014489c2020-06-02 20:09:13 -0700543}
544
545var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
546
547func init() {
548 android.RegisterSingletonType("lint",
549 func() android.Singleton { return &lintSingleton{} })
550}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700551
552func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
553 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
554
555 sort.Slice(paths, func(i, j int) bool {
556 return paths[i].String() < paths[j].String()
557 })
558
Colin Crossf1a035e2020-11-16 17:32:30 -0800559 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700560
Colin Crossf1a035e2020-11-16 17:32:30 -0800561 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700562 FlagWithOutput("-o ", outputPath).
563 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800564 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700565
Colin Crossf1a035e2020-11-16 17:32:30 -0800566 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700567}