blob: 938e2b0d7677c7b7af4cf554950a53b1e72d1a63 [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
185
186 deps android.Paths
187
188 remoteInputs android.Paths
189 remoteRSPInputs android.Paths
190}
191
Colin Cross9b93af42021-03-10 10:40:58 -0800192func lintRBEExecStrategy(ctx android.ModuleContext) string {
193 return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
194}
195
Colin Cross31972dc2021-03-04 10:44:12 -0800196func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
197 var deps android.Paths
198 var remoteInputs android.Paths
199 var remoteRSPInputs android.Paths
200
201 // Paths passed to trackInputDependency will be added as dependencies of the rule that runs
202 // lint and passed as inputs to the remote execution proxy.
203 trackInputDependency := func(paths ...android.Path) {
204 deps = append(deps, paths...)
205 remoteInputs = append(remoteInputs, paths...)
206 }
207
208 // Paths passed to trackRSPDependency will be added as dependencies of the rule that runs
209 // lint, but the RSP file will be used by the remote execution proxy to find the files so that
210 // it doesn't overflow command line limits.
211 trackRSPDependency := func(paths android.Paths, rsp android.Path) {
212 deps = append(deps, paths...)
213 remoteRSPInputs = append(remoteRSPInputs, rsp)
214 }
Colin Cross014489c2020-06-02 20:09:13 -0700215
216 var resourcesList android.WritablePath
217 if len(l.resources) > 0 {
218 // The list of resources may be too long to put on the command line, but
219 // we can't use the rsp file because it is already being used for srcs.
220 // Insert a second rule to write out the list of resources to a file.
Colin Cross1661aff2021-03-12 17:56:51 -0800221 resourcesList = android.PathForModuleOut(ctx, "resources.list")
Colin Crossf1a035e2020-11-16 17:32:30 -0800222 resListRule := android.NewRuleBuilder(pctx, ctx)
Colin Cross70c47412021-03-12 17:48:14 -0800223 resListRule.Command().Text("cp").
224 FlagWithRspFileInputList("", resourcesList.ReplaceExtension(ctx, "rsp"), l.resources).
225 Output(resourcesList)
Colin Crossf1a035e2020-11-16 17:32:30 -0800226 resListRule.Build("lint_resources_list", "lint resources list")
Colin Cross31972dc2021-03-04 10:44:12 -0800227 trackRSPDependency(l.resources, resourcesList)
Colin Cross014489c2020-06-02 20:09:13 -0700228 }
229
Colin Cross31972dc2021-03-04 10:44:12 -0800230 projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
Colin Cross014489c2020-06-02 20:09:13 -0700231 // Lint looks for a lint.xml file next to the project.xml file, give it one.
Colin Cross31972dc2021-03-04 10:44:12 -0800232 configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
233 cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
234 homeDir := android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700235
Colin Cross1661aff2021-03-12 17:56:51 -0800236 srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
Colin Cross014489c2020-06-02 20:09:13 -0700237 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
Colin Cross31972dc2021-03-04 10:44:12 -0800238 // TODO(ccross): this is a little fishy. The files extracted from the srcjars are referenced
239 // by the project.xml and used by the later lint rule, but the lint rule depends on the srcjars,
240 // not the extracted files.
241 trackRSPDependency(l.srcJars, srcJarList)
242
243 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
244 // lint separately.
245 srcsList := android.PathForModuleOut(ctx, "lint", "srcs.list")
Colin Cross70c47412021-03-12 17:48:14 -0800246 srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
247 rule.Command().Text("cp").
248 FlagWithRspFileInputList("", srcsListRsp, l.srcs).
249 Output(srcsList)
Colin Cross31972dc2021-03-04 10:44:12 -0800250 trackRSPDependency(l.srcs, srcsList)
Colin Cross1661aff2021-03-12 17:56:51 -0800251 rule.Temporary(srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700252
253 cmd := rule.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800254 BuiltTool("lint-project-xml").
Colin Cross014489c2020-06-02 20:09:13 -0700255 FlagWithOutput("--project_out ", projectXMLPath).
256 FlagWithOutput("--config_out ", configXMLPath).
257 FlagWithArg("--name ", ctx.ModuleName())
258
259 if l.library {
260 cmd.Flag("--library")
261 }
262 if l.test {
263 cmd.Flag("--test")
264 }
265 if l.manifest != nil {
Colin Cross1661aff2021-03-12 17:56:51 -0800266 cmd.FlagWithArg("--manifest ", cmd.PathForInput(l.manifest))
Colin Cross31972dc2021-03-04 10:44:12 -0800267 trackInputDependency(l.manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700268 }
269 if l.mergedManifest != nil {
Colin Cross1661aff2021-03-12 17:56:51 -0800270 cmd.FlagWithArg("--merged_manifest ", cmd.PathForInput(l.mergedManifest))
Colin Cross31972dc2021-03-04 10:44:12 -0800271 trackInputDependency(l.mergedManifest)
Colin Cross014489c2020-06-02 20:09:13 -0700272 }
273
Colin Cross31972dc2021-03-04 10:44:12 -0800274 cmd.FlagWithInput("--srcs ", srcsList)
Colin Cross014489c2020-06-02 20:09:13 -0700275
276 cmd.FlagWithInput("--generated_srcs ", srcJarList)
Colin Cross014489c2020-06-02 20:09:13 -0700277
278 if resourcesList != nil {
279 cmd.FlagWithInput("--resources ", resourcesList)
280 }
281
282 if l.classes != nil {
Colin Cross1661aff2021-03-12 17:56:51 -0800283 cmd.FlagWithArg("--classes ", cmd.PathForInput(l.classes))
Colin Cross31972dc2021-03-04 10:44:12 -0800284 trackInputDependency(l.classes)
Colin Cross014489c2020-06-02 20:09:13 -0700285 }
286
Colin Cross1661aff2021-03-12 17:56:51 -0800287 cmd.FlagForEachArg("--classpath ", cmd.PathsForInputs(l.classpath))
Colin Cross31972dc2021-03-04 10:44:12 -0800288 trackInputDependency(l.classpath...)
Colin Cross014489c2020-06-02 20:09:13 -0700289
Colin Cross1661aff2021-03-12 17:56:51 -0800290 cmd.FlagForEachArg("--extra_checks_jar ", cmd.PathsForInputs(l.extraLintCheckJars))
Colin Cross31972dc2021-03-04 10:44:12 -0800291 trackInputDependency(l.extraLintCheckJars...)
Colin Cross014489c2020-06-02 20:09:13 -0700292
Colin Cross1661aff2021-03-12 17:56:51 -0800293 cmd.FlagWithArg("--root_dir ", "$PWD")
Colin Crossc31efeb2020-06-23 10:25:26 -0700294
295 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
296 // the root dir is not set.
297 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700298
299 cmd.FlagWithInput("@",
300 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
301
302 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
303 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
304 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
305 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
306
Colin Cross31972dc2021-03-04 10:44:12 -0800307 return lintPaths{
308 projectXML: projectXMLPath,
309 configXML: configXMLPath,
310 cacheDir: cacheDir,
311 homeDir: homeDir,
312
313 deps: deps,
314
315 remoteInputs: remoteInputs,
316 remoteRSPInputs: remoteRSPInputs,
317 }
318
Colin Cross014489c2020-06-02 20:09:13 -0700319}
320
Liz Kammer20ebfb42020-07-28 11:32:07 -0700321// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700322// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
Colin Cross1661aff2021-03-12 17:56:51 -0800323func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700324 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
325
326 rule.Command().Text("(").
327 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
328 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
329 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
330 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
331 l.minSdkVersion, l.targetSdkVersion).
332 Text(`echo "</manifest>"`).
333 Text(") >").Output(manifestPath)
334
335 return manifestPath
336}
337
338func (l *linter) lint(ctx android.ModuleContext) {
339 if !l.enabled() {
340 return
341 }
342
Colin Cross92e4b462020-06-18 15:56:48 -0700343 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
344 for _, extraLintCheckModule := range extraLintCheckModules {
Colin Crossdcf71b22021-02-01 13:59:03 -0800345 if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
346 dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
347 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
Colin Cross92e4b462020-06-18 15:56:48 -0700348 } else {
349 ctx.PropertyErrorf("lint.extra_check_modules",
350 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
351 }
352 }
353
Colin Cross1661aff2021-03-12 17:56:51 -0800354 rule := android.NewRuleBuilder(pctx, ctx).
355 Sbox(android.PathForModuleOut(ctx, "lint"),
356 android.PathForModuleOut(ctx, "lint.sbox.textproto")).
357 SandboxInputs()
358
359 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
360 pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
361 rule.Remoteable(android.RemoteRuleSupports{RBE: true})
362 rule.Rewrapper(&remoteexec.REParams{
363 Labels: map[string]string{"type": "tool", "name": "lint"},
364 ExecStrategy: lintRBEExecStrategy(ctx),
365 ToolchainInputs: []string{config.JavaCmd(ctx).String()},
366 EnvironmentVariables: []string{
367 "LANG",
368 },
369 Platform: map[string]string{remoteexec.PoolKey: pool},
370 })
371 }
Colin Cross014489c2020-06-02 20:09:13 -0700372
373 if l.manifest == nil {
374 manifest := l.generateManifest(ctx, rule)
375 l.manifest = manifest
Colin Cross1661aff2021-03-12 17:56:51 -0800376 rule.Temporary(manifest)
Colin Cross014489c2020-06-02 20:09:13 -0700377 }
378
Colin Cross31972dc2021-03-04 10:44:12 -0800379 lintPaths := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700380
Colin Cross1661aff2021-03-12 17:56:51 -0800381 html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
382 text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
383 xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
Colin Crossc0efd1d2020-07-03 11:56:24 -0700384
Colin Cross08dca382020-07-21 20:31:17 -0700385 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700386
387 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700388 if depLint, ok := dep.(lintDepSetsIntf); ok {
389 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700390 }
391 })
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())
394 rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross5c113d12021-03-04 10:01:34 -0800395 rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
Colin Cross014489c2020-06-02 20:09:13 -0700396
Colin Cross8a6ed372020-07-06 11:45:51 -0700397 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900398 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700399 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
400 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
401 } else {
402 annotationsZipPath = copiedAnnotationsZipPath(ctx)
403 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
404 }
405
Colin Cross31972dc2021-03-04 10:44:12 -0800406 cmd := rule.Command()
407
408 cmd.Flag("JAVA_OPTS=-Xmx3072m").
409 FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700410 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
Colin Cross31972dc2021-03-04 10:44:12 -0800411 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
412
Colin Cross1661aff2021-03-12 17:56:51 -0800413 cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
Colin Cross014489c2020-06-02 20:09:13 -0700414 Flag("--quiet").
Colin Cross31972dc2021-03-04 10:44:12 -0800415 FlagWithInput("--project ", lintPaths.projectXML).
416 FlagWithInput("--config ", lintPaths.configXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700417 FlagWithOutput("--html ", html).
418 FlagWithOutput("--text ", text).
419 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700420 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
421 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
422 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
423 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
424 Flag("--exitcode").
425 Flags(l.properties.Lint.Flags).
Colin Cross31972dc2021-03-04 10:44:12 -0800426 Implicit(annotationsZipPath).
427 Implicit(apiVersionsXMLPath).
428 Implicits(lintPaths.deps)
Colin Cross988dfcc2020-07-16 17:32:17 -0700429
Colin Cross1661aff2021-03-12 17:56:51 -0800430 rule.Temporary(lintPaths.projectXML)
431 rule.Temporary(lintPaths.configXML)
432
Colin Cross988dfcc2020-07-16 17:32:17 -0700433 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
434 cmd.FlagWithArg("--check ", checkOnly)
435 }
436
Pedro Loureiro5d190cc2021-02-15 15:41:33 +0000437 if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
438 var lintBaseline android.OptionalPath
439 if String(l.properties.Lint.Baseline_filename) != "" {
440 // if manually specified, we require the file to exist
441 lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
442 } else {
443 lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
444 }
445 if lintBaseline.Valid() {
446 cmd.FlagWithInput("--baseline ", lintBaseline.Path())
447 }
448 }
449
Colin Cross31972dc2021-03-04 10:44:12 -0800450 cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
Colin Cross014489c2020-06-02 20:09:13 -0700451
Colin Cross31972dc2021-03-04 10:44:12 -0800452 rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700453
Colin Crossf1a035e2020-11-16 17:32:30 -0800454 rule.Build("lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700455
Colin Crossc0efd1d2020-07-03 11:56:24 -0700456 l.outputs = lintOutputs{
457 html: html,
458 text: text,
459 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700460
Colin Cross08dca382020-07-21 20:31:17 -0700461 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700462 }
Colin Cross014489c2020-06-02 20:09:13 -0700463
Colin Crossc0efd1d2020-07-03 11:56:24 -0700464 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700465 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700466 }
467}
Colin Cross014489c2020-06-02 20:09:13 -0700468
Colin Cross08dca382020-07-21 20:31:17 -0700469func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
470 htmlList := depSets.HTML.ToSortedList()
471 textList := depSets.Text.ToSortedList()
472 xmlList := depSets.XML.ToSortedList()
473
474 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
475 return nil
476 }
477
478 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
479 lintZip(ctx, htmlList, htmlZip)
480
481 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
482 lintZip(ctx, textList, textZip)
483
484 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
485 lintZip(ctx, xmlList, xmlZip)
486
487 return android.Paths{htmlZip, textZip, xmlZip}
488}
489
Colin Cross014489c2020-06-02 20:09:13 -0700490type lintSingleton struct {
491 htmlZip android.WritablePath
492 textZip android.WritablePath
493 xmlZip android.WritablePath
494}
495
496func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
497 l.generateLintReportZips(ctx)
498 l.copyLintDependencies(ctx)
499}
500
501func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900502 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700503 return
504 }
505
506 var frameworkDocStubs android.Module
507 ctx.VisitAllModules(func(m android.Module) {
508 if ctx.ModuleName(m) == "framework-doc-stubs" {
509 if frameworkDocStubs == nil {
510 frameworkDocStubs = m
511 } else {
512 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
513 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
514 }
515 }
516 })
517
518 if frameworkDocStubs == nil {
519 if !ctx.Config().AllowMissingDependencies() {
520 ctx.Errorf("lint: missing framework-doc-stubs")
521 }
522 return
523 }
524
525 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800526 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700527 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700528 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700529 })
530
531 ctx.Build(pctx, android.BuildParams{
Colin Cross00d93b12021-03-04 10:00:09 -0800532 Rule: android.CpIfChanged,
Colin Cross014489c2020-06-02 20:09:13 -0700533 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700534 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700535 })
536}
537
Colin Cross8a6ed372020-07-06 11:45:51 -0700538func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700539 return android.PathForOutput(ctx, "lint", "annotations.zip")
540}
541
Colin Cross8a6ed372020-07-06 11:45:51 -0700542func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700543 return android.PathForOutput(ctx, "lint", "api_versions.xml")
544}
545
546func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700547 if ctx.Config().UnbundledBuild() {
548 return
549 }
550
Colin Cross014489c2020-06-02 20:09:13 -0700551 var outputs []*lintOutputs
552 var dirs []string
553 ctx.VisitAllModules(func(m android.Module) {
Jingwen Chencda22c92020-11-23 00:22:30 -0500554 if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
Colin Cross014489c2020-06-02 20:09:13 -0700555 return
556 }
557
Colin Cross56a83212020-09-15 18:30:11 -0700558 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
559 apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
560 if apexInfo.IsForPlatform() {
561 // There are stray platform variants of modules in apexes that are not available for
562 // the platform, and they sometimes can't be built. Don't depend on them.
563 return
564 }
Colin Cross014489c2020-06-02 20:09:13 -0700565 }
566
Colin Cross08dca382020-07-21 20:31:17 -0700567 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700568 outputs = append(outputs, l.lintOutputs())
569 }
570 })
571
572 dirs = android.SortedUniqueStrings(dirs)
573
574 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
575 var paths android.Paths
576
577 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700578 if p := get(output); p != nil {
579 paths = append(paths, p)
580 }
Colin Cross014489c2020-06-02 20:09:13 -0700581 }
582
Colin Crossc0efd1d2020-07-03 11:56:24 -0700583 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700584 }
585
586 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
587 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
588
589 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
590 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
591
592 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
593 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
594
595 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
596}
597
598func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700599 if !ctx.Config().UnbundledBuild() {
600 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
601 }
Colin Cross014489c2020-06-02 20:09:13 -0700602}
603
604var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
605
606func init() {
607 android.RegisterSingletonType("lint",
608 func() android.Singleton { return &lintSingleton{} })
609}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700610
611func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
612 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
613
614 sort.Slice(paths, func(i, j int) bool {
615 return paths[i].String() < paths[j].String()
616 })
617
Colin Crossf1a035e2020-11-16 17:32:30 -0800618 rule := android.NewRuleBuilder(pctx, ctx)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700619
Colin Crossf1a035e2020-11-16 17:32:30 -0800620 rule.Command().BuiltTool("soong_zip").
Colin Crossc0efd1d2020-07-03 11:56:24 -0700621 FlagWithOutput("-o ", outputPath).
622 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross70c47412021-03-12 17:48:14 -0800623 FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700624
Colin Crossf1a035e2020-11-16 17:32:30 -0800625 rule.Build(outputPath.Base(), outputPath.Base())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700626}