blob: f9a89d0f7e547450b754b71fee23abbcede34b3e [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 Cross31972dc2021-03-04 10:44:12 -0800177type lintPaths struct {
178 projectXML android.WritablePath
179 configXML android.WritablePath
180 cacheDir android.WritablePath
181 homeDir android.WritablePath
182 srcjarDir android.WritablePath
183
184 deps android.Paths
185
186 remoteInputs android.Paths
187 remoteRSPInputs android.Paths
188}
189
190func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
191 var deps android.Paths
192 var remoteInputs android.Paths
193 var remoteRSPInputs android.Paths
194
195 // Paths passed to trackInputDependency will be added as dependencies of the rule that runs
196 // lint and passed as inputs to the remote execution proxy.
197 trackInputDependency := func(paths ...android.Path) {
198 deps = append(deps, paths...)
199 remoteInputs = append(remoteInputs, paths...)
200 }
201
202 // Paths passed to trackRSPDependency will be added as dependencies of the rule that runs
203 // lint, but the RSP file will be used by the remote execution proxy to find the files so that
204 // it doesn't overflow command line limits.
205 trackRSPDependency := func(paths android.Paths, rsp android.Path) {
206 deps = append(deps, paths...)
207 remoteRSPInputs = append(remoteRSPInputs, rsp)
208 }
Colin Cross014489c2020-06-02 20:09:13 -0700209
210 var resourcesList android.WritablePath
211 if len(l.resources) > 0 {
212 // The list of resources may be too long to put on the command line, but
213 // we can't use the rsp file because it is already being used for srcs.
214 // Insert a second rule to write out the list of resources to a file.
215 resourcesList = android.PathForModuleOut(ctx, "lint", "resources.list")
Colin Crossf1a035e2020-11-16 17:32:30 -0800216 resListRule := android.NewRuleBuilder(pctx, ctx)
Colin Cross014489c2020-06-02 20:09:13 -0700217 resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList)
Colin Crossf1a035e2020-11-16 17:32:30 -0800218 resListRule.Build("lint_resources_list", "lint resources list")
Colin Cross31972dc2021-03-04 10:44:12 -0800219 trackRSPDependency(l.resources, resourcesList)
Colin Cross014489c2020-06-02 20:09:13 -0700220 }
221
Colin Cross31972dc2021-03-04 10:44:12 -0800222 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700223 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800224 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
225 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
226 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700227
228 srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars")
229 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
Colin Cross31972dc2021-03-04 10:44:12 -0800230 // TODO(ccross): this is a little fishy. The files extracted from the srcjars are referenced
231 // by the project.xml and used by the later lint rule, but the lint rule depends on the srcjars,
232 // not the extracted files.
233 trackRSPDependency(l.srcJars, srcJarList)
234
235 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
236 // lint separately.
237 srcsList := android.PathForModuleOut(ctx, "lint", "srcs.list")
238 rule.Command().Text("cp").FlagWithRspFileInputList("", l.srcs).Output(srcsList)
239 trackRSPDependency(l.srcs, srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700240
241 cmd := rule.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800242 BuiltTool("lint-project-xml").
Colin Cross014489c2020-06-02 20:09:13 -0700243 FlagWithOutput("--project_out ", projectXMLPath).
244 FlagWithOutput("--config_out ", configXMLPath).
245 FlagWithArg("--name ", ctx.ModuleName())
246
247 if l.library {
248 cmd.Flag("--library")
249 }
250 if l.test {
251 cmd.Flag("--test")
252 }
253 if l.manifest != nil {
Colin Cross014489c2020-06-02 20:09:13 -0700254 cmd.FlagWithArg("--manifest ", l.manifest.String())
Colin Cross31972dc2021-03-04 10:44:12 -0800255 trackInputDependency(l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700256 }
257 if l.mergedManifest != nil {
Colin Cross014489c2020-06-02 20:09:13 -0700258 cmd.FlagWithArg("--merged_manifest ", l.mergedManifest.String())
Colin Cross31972dc2021-03-04 10:44:12 -0800259 trackInputDependency(l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700260 }
261
Colin Cross31972dc2021-03-04 10:44:12 -0800262 cmd.FlagWithInput("--srcs ", srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700263
264 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700265
266 if resourcesList != nil {
267 cmd.FlagWithInput("--resources ", resourcesList)
268 }
269
270 if l.classes != nil {
Colin Cross014489c2020-06-02 20:09:13 -0700271 cmd.FlagWithArg("--classes ", l.classes.String())
Colin Cross31972dc2021-03-04 10:44:12 -0800272 trackInputDependency(l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700273 }
274
275 cmd.FlagForEachArg("--classpath ", l.classpath.Strings())
Colin Cross31972dc2021-03-04 10:44:12 -0800276 trackInputDependency(l.classpath...)
Colin Cross014489c2020-06-02 20:09:13 -0700277
278 cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
Colin Cross31972dc2021-03-04 10:44:12 -0800279 trackInputDependency(l.extraLintCheckJars...)
Colin Cross014489c2020-06-02 20:09:13 -0700280
Colin Cross31972dc2021-03-04 10:44:12 -0800281 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
282 // TODO(b/181912787): remove these and use "." instead.
283 cmd.FlagWithArg("--root_dir ", "/b/f/w")
284 } else {
285 cmd.FlagWithArg("--root_dir ", "$PWD")
286 }
Colin Crossc31efeb2020-06-23 10:25:26 -0700287
288 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
289 // the root dir is not set.
290 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700291
292 cmd.FlagWithInput("@",
293 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
294
295 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
296 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
297 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
298 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
299
Colin Cross31972dc2021-03-04 10:44:12 -0800300 return lintPaths{
301 projectXML: projectXMLPath,
302 configXML: configXMLPath,
303 cacheDir: cacheDir,
304 homeDir: homeDir,
305
306 deps: deps,
307
308 remoteInputs: remoteInputs,
309 remoteRSPInputs: remoteRSPInputs,
310 }
311
Colin Cross014489c2020-06-02 20:09:13 -0700312}
313
Liz Kammer20ebfb42020-07-28 11:32:07 -0700314// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700315// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
316func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
317 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
318
319 rule.Command().Text("(").
320 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
321 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
322 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
323 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
324 l.minSdkVersion, l.targetSdkVersion).
325 Text(`echo "</manifest>"`).
326 Text(") >").Output(manifestPath)
327
328 return manifestPath
329}
330
331func (l *linter) lint(ctx android.ModuleContext) {
332 if !l.enabled() {
333 return
334 }
335
Colin Cross92e4b462020-06-18 15:56:48 -0700336 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
337 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800338 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
339 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
340 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700341 } else {
342 ctx.PropertyErrorf("lint.extra_check_modules",
343 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
344 }
345 }
346
Colin Crossf1a035e2020-11-16 17:32:30 -0800347 rule := android.NewRuleBuilder(pctx, ctx)
Colin Cross014489c2020-06-02 20:09:13 -0700348
349 if l.manifest == nil {
350 manifest := l.generateManifest(ctx, rule)
351 l.manifest = manifest
352 }
353
Colin Cross31972dc2021-03-04 10:44:12 -0800354 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700355
Colin Crossc0efd1d2020-07-03 11:56:24 -0700356 html := android.PathForModuleOut(ctx, "lint-report.html")
357 text := android.PathForModuleOut(ctx, "lint-report.txt")
358 xml := android.PathForModuleOut(ctx, "lint-report.xml")
359
Colin Cross08dca382020-07-21 20:31:17 -0700360 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700361
362 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700363 if depLint, ok := dep.(lintDepSetsIntf); ok {
364 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700365 }
366 })
Colin Cross014489c2020-06-02 20:09:13 -0700367
Colin Cross31972dc2021-03-04 10:44:12 -0800368 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
369 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800370 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700371
Colin Cross8a6ed372020-07-06 11:45:51 -0700372 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900373 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700374 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
375 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
376 } else {
377 annotationsZipPath = copiedAnnotationsZipPath(ctx)
378 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
379 }
380
Colin Cross31972dc2021-03-04 10:44:12 -0800381 cmd := rule.Command()
382
383 cmd.Flag("JAVA_OPTS=-Xmx3072m").
384 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700385 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800386 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
387
388 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
389 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
390 // TODO(b/181912787): this should be local fallback once the hack that passes /b/f/w in project.xml
391 // is removed.
392 execStrategy := ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.RemoteExecStrategy)
393 labels := map[string]string{"type": "tool", "name": "lint"}
394 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
395 remoteInputs := lintPaths.remoteInputs
396 remoteInputs = append(remoteInputs,
397 lintPaths.projectXML,
398 lintPaths.configXML,
399 lintPaths.homeDir,
400 lintPaths.cacheDir,
401 ctx.Config().HostJavaToolPath(ctx, "lint.jar"),
402 annotationsZipPath,
403 apiVersionsXMLPath,
404 )
405
406 cmd.Text((&remoteexec.REParams{
407 Labels: labels,
408 ExecStrategy: execStrategy,
409 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
410 Inputs: remoteInputs.Strings(),
411 OutputFiles: android.Paths{html, text, xml}.Strings(),
412 RSPFile: strings.Join(lintPaths.remoteRSPInputs.Strings(), ","),
413 EnvironmentVariables: []string{
414 "JAVA_OPTS",
415 "ANDROID_SDK_HOME",
416 "SDK_ANNOTATIONS",
417 "LINT_OPTS",
418 },
419 Platform: map[string]string{remoteexec.PoolKey: pool},
420 }).NoVarTemplate(ctx.Config()))
421 }
422
423 cmd.BuiltTool("lint").
Colin Cross014489c2020-06-02 20:09:13 -0700424 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800425 FlagWithInput("--project ", lintPaths.projectXML).
426 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700427 FlagWithOutput("--html ", html).
428 FlagWithOutput("--text ", text).
429 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700430 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
431 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
432 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
433 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
434 Flag("--exitcode").
435 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800436 Implicit(annotationsZipPath).
437 Implicit(apiVersionsXMLPath).
438 Implicits(lintPaths.deps)
Colin Cross988dfcc2020-07-16 17:32:17 -0700439
440 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
441 cmd.FlagWithArg("--check ", checkOnly)
442 }
443
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000444 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
445 var lintBaseline android.OptionalPath
446 if String(l.properties.Lint.Baseline_filename) != "" {
447 // if manually specified, we require the file to exist
448 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
449 } else {
450 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
451 }
452 if lintBaseline.Valid() {
453 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
454 }
455 }
456
Colin Cross31972dc2021-03-04 10:44:12 -0800457 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700458
Colin Cross31972dc2021-03-04 10:44:12 -0800459 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700460
Colin Crossf1a035e2020-11-16 17:32:30 -0800461 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700462
Colin Crossc0efd1d2020-07-03 11:56:24 -0700463 l.outputs = lintOutputs{
464 html: html,
465 text: text,
466 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700467
Colin Cross08dca382020-07-21 20:31:17 -0700468 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700469 }
Colin Cross014489c2020-06-02 20:09:13 -0700470
Colin Crossc0efd1d2020-07-03 11:56:24 -0700471 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700472 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700473 }
474}
Colin Cross014489c2020-06-02 20:09:13 -0700475
Colin Cross08dca382020-07-21 20:31:17 -0700476func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
477 htmlList := depSets.HTML.ToSortedList()
478 textList := depSets.Text.ToSortedList()
479 xmlList := depSets.XML.ToSortedList()
480
481 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
482 return nil
483 }
484
485 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
486 lintZip(ctx, htmlList, htmlZip)
487
488 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
489 lintZip(ctx, textList, textZip)
490
491 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
492 lintZip(ctx, xmlList, xmlZip)
493
494 return android.Paths{htmlZip, textZip, xmlZip}
495}
496
Colin Cross014489c2020-06-02 20:09:13 -0700497type lintSingleton struct {
498 htmlZip android.WritablePath
499 textZip android.WritablePath
500 xmlZip android.WritablePath
501}
502
503func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
504 l.generateLintReportZips(ctx)
505 l.copyLintDependencies(ctx)
506}
507
508func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900509 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700510 return
511 }
512
513 var frameworkDocStubs android.Module
514 ctx.VisitAllModules(func(m android.Module) {
515 if ctx.ModuleName(m) == "framework-doc-stubs" {
516 if frameworkDocStubs == nil {
517 frameworkDocStubs = m
518 } else {
519 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
520 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
521 }
522 }
523 })
524
525 if frameworkDocStubs == nil {
526 if !ctx.Config().AllowMissingDependencies() {
527 ctx.Errorf("lint: missing framework-doc-stubs")
528 }
529 return
530 }
531
532 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800533 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700534 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700535 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700536 })
537
538 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800539 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700540 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700541 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700542 })
543}
544
Colin Cross8a6ed372020-07-06 11:45:51 -0700545func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700546 return android.PathForOutput(ctx, "lint", "annotations.zip")
547}
548
Colin Cross8a6ed372020-07-06 11:45:51 -0700549func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700550 return android.PathForOutput(ctx, "lint", "api_versions.xml")
551}
552
553func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700554 if ctx.Config().UnbundledBuild() {
555 return
556 }
557
Colin Cross014489c2020-06-02 20:09:13 -0700558 var outputs []*lintOutputs
559 var dirs []string
560 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500561 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700562 return
563 }
564
Colin Cross56a83212020-09-15 18:30:11 -0700565 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
566 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
567 if apexInfo.IsForPlatform() {
568 // There are stray platform variants of modules in apexes that are not available for
569 // the platform, and they sometimes can't be built. Don't depend on them.
570 return
571 }
Colin Cross014489c2020-06-02 20:09:13 -0700572 }
573
Colin Cross08dca382020-07-21 20:31:17 -0700574 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700575 outputs = append(outputs, l.lintOutputs())
576 }
577 })
578
579 dirs = android.SortedUniqueStrings(dirs)
580
581 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
582 var paths android.Paths
583
584 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700585 if p := get(output); p != nil {
586 paths = append(paths, p)
587 }
Colin Cross014489c2020-06-02 20:09:13 -0700588 }
589
Colin Crossc0efd1d2020-07-03 11:56:24 -0700590 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700591 }
592
593 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
594 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
595
596 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
597 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
598
599 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
600 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
601
602 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
603}
604
605func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700606 if !ctx.Config().UnbundledBuild() {
607 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
608 }
Colin Cross014489c2020-06-02 20:09:13 -0700609}
610
611var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
612
613func init() {
614 android.RegisterSingletonType("lint",
615 func() android.Singleton { return &lintSingleton{} })
616}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700617
618func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
619 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
620
621 sort.Slice(paths, func(i, j int) bool {
622 return paths[i].String() < paths[j].String()
623 })
624
Colin Crossf1a035e2020-11-16 17:32:30 -0800625 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700626
Colin Crossf1a035e2020-11-16 17:32:30 -0800627 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700628 FlagWithOutput("-o ", outputPath).
629 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross053fca12020-08-19 13:51:47 -0700630 FlagWithRspFileInputList("-r ", paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700631
Colin Crossf1a035e2020-11-16 17:32:30 -0800632 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700633}