xref: /aosp_15_r20/build/soong/java/lint.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2020 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage java
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"sort"
20*333d2b36SAndroid Build Coastguard Worker	"strings"
21*333d2b36SAndroid Build Coastguard Worker
22*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
23*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/depset"
24*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
27*333d2b36SAndroid Build Coastguard Worker	"android/soong/java/config"
28*333d2b36SAndroid Build Coastguard Worker	"android/soong/remoteexec"
29*333d2b36SAndroid Build Coastguard Worker)
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard Worker// lint checks automatically enforced for modules that have different min_sdk_version than
32*333d2b36SAndroid Build Coastguard Worker// sdk_version
33*333d2b36SAndroid Build Coastguard Workervar updatabilityChecks = []string{"NewApi"}
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Workertype LintProperties struct {
36*333d2b36SAndroid Build Coastguard Worker	// Controls for running Android Lint on the module.
37*333d2b36SAndroid Build Coastguard Worker	Lint struct {
38*333d2b36SAndroid Build Coastguard Worker
39*333d2b36SAndroid Build Coastguard Worker		// If true, run Android Lint on the module.  Defaults to true.
40*333d2b36SAndroid Build Coastguard Worker		Enabled *bool
41*333d2b36SAndroid Build Coastguard Worker
42*333d2b36SAndroid Build Coastguard Worker		// Flags to pass to the Android Lint tool.
43*333d2b36SAndroid Build Coastguard Worker		Flags []string
44*333d2b36SAndroid Build Coastguard Worker
45*333d2b36SAndroid Build Coastguard Worker		// Checks that should be treated as fatal.
46*333d2b36SAndroid Build Coastguard Worker		Fatal_checks []string
47*333d2b36SAndroid Build Coastguard Worker
48*333d2b36SAndroid Build Coastguard Worker		// Checks that should be treated as errors.
49*333d2b36SAndroid Build Coastguard Worker		Error_checks []string
50*333d2b36SAndroid Build Coastguard Worker
51*333d2b36SAndroid Build Coastguard Worker		// Checks that should be treated as warnings.
52*333d2b36SAndroid Build Coastguard Worker		Warning_checks []string
53*333d2b36SAndroid Build Coastguard Worker
54*333d2b36SAndroid Build Coastguard Worker		// Checks that should be skipped.
55*333d2b36SAndroid Build Coastguard Worker		Disabled_checks []string
56*333d2b36SAndroid Build Coastguard Worker
57*333d2b36SAndroid Build Coastguard Worker		// Modules that provide extra lint checks
58*333d2b36SAndroid Build Coastguard Worker		Extra_check_modules []string
59*333d2b36SAndroid Build Coastguard Worker
60*333d2b36SAndroid Build Coastguard Worker		// The lint baseline file to use. If specified, lint warnings listed in this file will be
61*333d2b36SAndroid Build Coastguard Worker		// suppressed during lint checks.
62*333d2b36SAndroid Build Coastguard Worker		Baseline_filename *string
63*333d2b36SAndroid Build Coastguard Worker
64*333d2b36SAndroid Build Coastguard Worker		// If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
65*333d2b36SAndroid Build Coastguard Worker		Strict_updatability_linting *bool
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Worker		// Treat the code in this module as test code for @VisibleForTesting enforcement.
68*333d2b36SAndroid Build Coastguard Worker		// This will be true by default for test module types, false otherwise.
69*333d2b36SAndroid Build Coastguard Worker		// If soong gets support for testonly, this flag should be replaced with that.
70*333d2b36SAndroid Build Coastguard Worker		Test *bool
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker		// Whether to ignore the exit code of Android lint. This is the --exit_code
73*333d2b36SAndroid Build Coastguard Worker		// option. Defaults to false.
74*333d2b36SAndroid Build Coastguard Worker		Suppress_exit_code *bool
75*333d2b36SAndroid Build Coastguard Worker	}
76*333d2b36SAndroid Build Coastguard Worker}
77*333d2b36SAndroid Build Coastguard Worker
78*333d2b36SAndroid Build Coastguard Workertype linter struct {
79*333d2b36SAndroid Build Coastguard Worker	name                    string
80*333d2b36SAndroid Build Coastguard Worker	manifest                android.Path
81*333d2b36SAndroid Build Coastguard Worker	mergedManifest          android.Path
82*333d2b36SAndroid Build Coastguard Worker	srcs                    android.Paths
83*333d2b36SAndroid Build Coastguard Worker	srcJars                 android.Paths
84*333d2b36SAndroid Build Coastguard Worker	resources               android.Paths
85*333d2b36SAndroid Build Coastguard Worker	classpath               android.Paths
86*333d2b36SAndroid Build Coastguard Worker	classes                 android.Path
87*333d2b36SAndroid Build Coastguard Worker	extraLintCheckJars      android.Paths
88*333d2b36SAndroid Build Coastguard Worker	library                 bool
89*333d2b36SAndroid Build Coastguard Worker	minSdkVersion           android.ApiLevel
90*333d2b36SAndroid Build Coastguard Worker	targetSdkVersion        android.ApiLevel
91*333d2b36SAndroid Build Coastguard Worker	compileSdkVersion       android.ApiLevel
92*333d2b36SAndroid Build Coastguard Worker	compileSdkKind          android.SdkKind
93*333d2b36SAndroid Build Coastguard Worker	javaLanguageLevel       string
94*333d2b36SAndroid Build Coastguard Worker	kotlinLanguageLevel     string
95*333d2b36SAndroid Build Coastguard Worker	properties              LintProperties
96*333d2b36SAndroid Build Coastguard Worker	extraMainlineLintErrors []string
97*333d2b36SAndroid Build Coastguard Worker	compile_data            android.Paths
98*333d2b36SAndroid Build Coastguard Worker
99*333d2b36SAndroid Build Coastguard Worker	reports android.Paths
100*333d2b36SAndroid Build Coastguard Worker
101*333d2b36SAndroid Build Coastguard Worker	buildModuleReportZip bool
102*333d2b36SAndroid Build Coastguard Worker}
103*333d2b36SAndroid Build Coastguard Worker
104*333d2b36SAndroid Build Coastguard Workertype LintDepSets struct {
105*333d2b36SAndroid Build Coastguard Worker	HTML, Text, XML, Baseline depset.DepSet[android.Path]
106*333d2b36SAndroid Build Coastguard Worker}
107*333d2b36SAndroid Build Coastguard Worker
108*333d2b36SAndroid Build Coastguard Workertype LintDepSetsBuilder struct {
109*333d2b36SAndroid Build Coastguard Worker	HTML, Text, XML, Baseline *depset.Builder[android.Path]
110*333d2b36SAndroid Build Coastguard Worker}
111*333d2b36SAndroid Build Coastguard Worker
112*333d2b36SAndroid Build Coastguard Workerfunc NewLintDepSetBuilder() LintDepSetsBuilder {
113*333d2b36SAndroid Build Coastguard Worker	return LintDepSetsBuilder{
114*333d2b36SAndroid Build Coastguard Worker		HTML:     depset.NewBuilder[android.Path](depset.POSTORDER),
115*333d2b36SAndroid Build Coastguard Worker		Text:     depset.NewBuilder[android.Path](depset.POSTORDER),
116*333d2b36SAndroid Build Coastguard Worker		XML:      depset.NewBuilder[android.Path](depset.POSTORDER),
117*333d2b36SAndroid Build Coastguard Worker		Baseline: depset.NewBuilder[android.Path](depset.POSTORDER),
118*333d2b36SAndroid Build Coastguard Worker	}
119*333d2b36SAndroid Build Coastguard Worker}
120*333d2b36SAndroid Build Coastguard Worker
121*333d2b36SAndroid Build Coastguard Workerfunc (l LintDepSetsBuilder) Direct(html, text, xml android.Path, baseline android.OptionalPath) LintDepSetsBuilder {
122*333d2b36SAndroid Build Coastguard Worker	l.HTML.Direct(html)
123*333d2b36SAndroid Build Coastguard Worker	l.Text.Direct(text)
124*333d2b36SAndroid Build Coastguard Worker	l.XML.Direct(xml)
125*333d2b36SAndroid Build Coastguard Worker	if baseline.Valid() {
126*333d2b36SAndroid Build Coastguard Worker		l.Baseline.Direct(baseline.Path())
127*333d2b36SAndroid Build Coastguard Worker	}
128*333d2b36SAndroid Build Coastguard Worker	return l
129*333d2b36SAndroid Build Coastguard Worker}
130*333d2b36SAndroid Build Coastguard Worker
131*333d2b36SAndroid Build Coastguard Workerfunc (l LintDepSetsBuilder) Transitive(info *LintInfo) LintDepSetsBuilder {
132*333d2b36SAndroid Build Coastguard Worker	l.HTML.Transitive(info.TransitiveHTML)
133*333d2b36SAndroid Build Coastguard Worker	l.Text.Transitive(info.TransitiveText)
134*333d2b36SAndroid Build Coastguard Worker	l.XML.Transitive(info.TransitiveXML)
135*333d2b36SAndroid Build Coastguard Worker	l.Baseline.Transitive(info.TransitiveBaseline)
136*333d2b36SAndroid Build Coastguard Worker	return l
137*333d2b36SAndroid Build Coastguard Worker}
138*333d2b36SAndroid Build Coastguard Worker
139*333d2b36SAndroid Build Coastguard Workerfunc (l LintDepSetsBuilder) Build() LintDepSets {
140*333d2b36SAndroid Build Coastguard Worker	return LintDepSets{
141*333d2b36SAndroid Build Coastguard Worker		HTML:     l.HTML.Build(),
142*333d2b36SAndroid Build Coastguard Worker		Text:     l.Text.Build(),
143*333d2b36SAndroid Build Coastguard Worker		XML:      l.XML.Build(),
144*333d2b36SAndroid Build Coastguard Worker		Baseline: l.Baseline.Build(),
145*333d2b36SAndroid Build Coastguard Worker	}
146*333d2b36SAndroid Build Coastguard Worker}
147*333d2b36SAndroid Build Coastguard Worker
148*333d2b36SAndroid Build Coastguard Workertype lintDatabaseFiles struct {
149*333d2b36SAndroid Build Coastguard Worker	apiVersionsModule       string
150*333d2b36SAndroid Build Coastguard Worker	apiVersionsCopiedName   string
151*333d2b36SAndroid Build Coastguard Worker	apiVersionsPrebuiltPath string
152*333d2b36SAndroid Build Coastguard Worker	annotationsModule       string
153*333d2b36SAndroid Build Coastguard Worker	annotationCopiedName    string
154*333d2b36SAndroid Build Coastguard Worker	annotationPrebuiltpath  string
155*333d2b36SAndroid Build Coastguard Worker}
156*333d2b36SAndroid Build Coastguard Worker
157*333d2b36SAndroid Build Coastguard Workervar allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{
158*333d2b36SAndroid Build Coastguard Worker	android.SdkPublic: {
159*333d2b36SAndroid Build Coastguard Worker		apiVersionsModule:       "api_versions_public",
160*333d2b36SAndroid Build Coastguard Worker		apiVersionsCopiedName:   "api_versions_public.xml",
161*333d2b36SAndroid Build Coastguard Worker		apiVersionsPrebuiltPath: "prebuilts/sdk/current/public/data/api-versions.xml",
162*333d2b36SAndroid Build Coastguard Worker		annotationsModule:       "sdk-annotations.zip",
163*333d2b36SAndroid Build Coastguard Worker		annotationCopiedName:    "annotations-public.zip",
164*333d2b36SAndroid Build Coastguard Worker		annotationPrebuiltpath:  "prebuilts/sdk/current/public/data/annotations.zip",
165*333d2b36SAndroid Build Coastguard Worker	},
166*333d2b36SAndroid Build Coastguard Worker	android.SdkSystem: {
167*333d2b36SAndroid Build Coastguard Worker		apiVersionsModule:       "api_versions_system",
168*333d2b36SAndroid Build Coastguard Worker		apiVersionsCopiedName:   "api_versions_system.xml",
169*333d2b36SAndroid Build Coastguard Worker		apiVersionsPrebuiltPath: "prebuilts/sdk/current/system/data/api-versions.xml",
170*333d2b36SAndroid Build Coastguard Worker		annotationsModule:       "sdk-annotations-system.zip",
171*333d2b36SAndroid Build Coastguard Worker		annotationCopiedName:    "annotations-system.zip",
172*333d2b36SAndroid Build Coastguard Worker		annotationPrebuiltpath:  "prebuilts/sdk/current/system/data/annotations.zip",
173*333d2b36SAndroid Build Coastguard Worker	},
174*333d2b36SAndroid Build Coastguard Worker	android.SdkModule: {
175*333d2b36SAndroid Build Coastguard Worker		apiVersionsModule:       "api_versions_module_lib",
176*333d2b36SAndroid Build Coastguard Worker		apiVersionsCopiedName:   "api_versions_module_lib.xml",
177*333d2b36SAndroid Build Coastguard Worker		apiVersionsPrebuiltPath: "prebuilts/sdk/current/module-lib/data/api-versions.xml",
178*333d2b36SAndroid Build Coastguard Worker		annotationsModule:       "sdk-annotations-module-lib.zip",
179*333d2b36SAndroid Build Coastguard Worker		annotationCopiedName:    "annotations-module-lib.zip",
180*333d2b36SAndroid Build Coastguard Worker		annotationPrebuiltpath:  "prebuilts/sdk/current/module-lib/data/annotations.zip",
181*333d2b36SAndroid Build Coastguard Worker	},
182*333d2b36SAndroid Build Coastguard Worker	android.SdkSystemServer: {
183*333d2b36SAndroid Build Coastguard Worker		apiVersionsModule:       "api_versions_system_server",
184*333d2b36SAndroid Build Coastguard Worker		apiVersionsCopiedName:   "api_versions_system_server.xml",
185*333d2b36SAndroid Build Coastguard Worker		apiVersionsPrebuiltPath: "prebuilts/sdk/current/system-server/data/api-versions.xml",
186*333d2b36SAndroid Build Coastguard Worker		annotationsModule:       "sdk-annotations-system-server.zip",
187*333d2b36SAndroid Build Coastguard Worker		annotationCopiedName:    "annotations-system-server.zip",
188*333d2b36SAndroid Build Coastguard Worker		annotationPrebuiltpath:  "prebuilts/sdk/current/system-server/data/annotations.zip",
189*333d2b36SAndroid Build Coastguard Worker	},
190*333d2b36SAndroid Build Coastguard Worker}
191*333d2b36SAndroid Build Coastguard Worker
192*333d2b36SAndroid Build Coastguard Workervar LintProvider = blueprint.NewProvider[*LintInfo]()
193*333d2b36SAndroid Build Coastguard Worker
194*333d2b36SAndroid Build Coastguard Workertype LintInfo struct {
195*333d2b36SAndroid Build Coastguard Worker	HTML              android.Path
196*333d2b36SAndroid Build Coastguard Worker	Text              android.Path
197*333d2b36SAndroid Build Coastguard Worker	XML               android.Path
198*333d2b36SAndroid Build Coastguard Worker	ReferenceBaseline android.Path
199*333d2b36SAndroid Build Coastguard Worker
200*333d2b36SAndroid Build Coastguard Worker	TransitiveHTML     depset.DepSet[android.Path]
201*333d2b36SAndroid Build Coastguard Worker	TransitiveText     depset.DepSet[android.Path]
202*333d2b36SAndroid Build Coastguard Worker	TransitiveXML      depset.DepSet[android.Path]
203*333d2b36SAndroid Build Coastguard Worker	TransitiveBaseline depset.DepSet[android.Path]
204*333d2b36SAndroid Build Coastguard Worker}
205*333d2b36SAndroid Build Coastguard Worker
206*333d2b36SAndroid Build Coastguard Workerfunc (l *linter) enabled() bool {
207*333d2b36SAndroid Build Coastguard Worker	return BoolDefault(l.properties.Lint.Enabled, true)
208*333d2b36SAndroid Build Coastguard Worker}
209*333d2b36SAndroid Build Coastguard Worker
210*333d2b36SAndroid Build Coastguard Workerfunc (l *linter) deps(ctx android.BottomUpMutatorContext) {
211*333d2b36SAndroid Build Coastguard Worker	if !l.enabled() {
212*333d2b36SAndroid Build Coastguard Worker		return
213*333d2b36SAndroid Build Coastguard Worker	}
214*333d2b36SAndroid Build Coastguard Worker
215*333d2b36SAndroid Build Coastguard Worker	extraCheckModules := l.properties.Lint.Extra_check_modules
216*333d2b36SAndroid Build Coastguard Worker
217*333d2b36SAndroid Build Coastguard Worker	if extraCheckModulesEnv := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); extraCheckModulesEnv != "" {
218*333d2b36SAndroid Build Coastguard Worker		extraCheckModules = append(extraCheckModules, strings.Split(extraCheckModulesEnv, ",")...)
219*333d2b36SAndroid Build Coastguard Worker	}
220*333d2b36SAndroid Build Coastguard Worker
221*333d2b36SAndroid Build Coastguard Worker	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
222*333d2b36SAndroid Build Coastguard Worker		extraLintCheckTag, extraCheckModules...)
223*333d2b36SAndroid Build Coastguard Worker}
224*333d2b36SAndroid Build Coastguard Worker
225*333d2b36SAndroid Build Coastguard Worker// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
226*333d2b36SAndroid Build Coastguard Worker// around.
227*333d2b36SAndroid Build Coastguard Workertype lintPaths struct {
228*333d2b36SAndroid Build Coastguard Worker	projectXML android.WritablePath
229*333d2b36SAndroid Build Coastguard Worker	configXML  android.WritablePath
230*333d2b36SAndroid Build Coastguard Worker	cacheDir   android.WritablePath
231*333d2b36SAndroid Build Coastguard Worker	homeDir    android.WritablePath
232*333d2b36SAndroid Build Coastguard Worker	srcjarDir  android.WritablePath
233*333d2b36SAndroid Build Coastguard Worker}
234*333d2b36SAndroid Build Coastguard Worker
235*333d2b36SAndroid Build Coastguard Workerfunc lintRBEExecStrategy(ctx android.ModuleContext) string {
236*333d2b36SAndroid Build Coastguard Worker	return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
237*333d2b36SAndroid Build Coastguard Worker}
238*333d2b36SAndroid Build Coastguard Worker
239*333d2b36SAndroid Build Coastguard Workerfunc (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path,
240*333d2b36SAndroid Build Coastguard Worker	baselines android.Paths) lintPaths {
241*333d2b36SAndroid Build Coastguard Worker
242*333d2b36SAndroid Build Coastguard Worker	projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
243*333d2b36SAndroid Build Coastguard Worker	// Lint looks for a lint.xml file next to the project.xml file, give it one.
244*333d2b36SAndroid Build Coastguard Worker	configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
245*333d2b36SAndroid Build Coastguard Worker	cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
246*333d2b36SAndroid Build Coastguard Worker	homeDir := android.PathForModuleOut(ctx, "lint", "home")
247*333d2b36SAndroid Build Coastguard Worker
248*333d2b36SAndroid Build Coastguard Worker	srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
249*333d2b36SAndroid Build Coastguard Worker	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
250*333d2b36SAndroid Build Coastguard Worker
251*333d2b36SAndroid Build Coastguard Worker	cmd := rule.Command().
252*333d2b36SAndroid Build Coastguard Worker		BuiltTool("lint_project_xml").
253*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--project_out ", projectXMLPath).
254*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--config_out ", configXMLPath).
255*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--name ", ctx.ModuleName())
256*333d2b36SAndroid Build Coastguard Worker
257*333d2b36SAndroid Build Coastguard Worker	if l.library {
258*333d2b36SAndroid Build Coastguard Worker		cmd.Flag("--library")
259*333d2b36SAndroid Build Coastguard Worker	}
260*333d2b36SAndroid Build Coastguard Worker	if proptools.BoolDefault(l.properties.Lint.Test, false) {
261*333d2b36SAndroid Build Coastguard Worker		cmd.Flag("--test")
262*333d2b36SAndroid Build Coastguard Worker	}
263*333d2b36SAndroid Build Coastguard Worker	if l.manifest != nil {
264*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithInput("--manifest ", l.manifest)
265*333d2b36SAndroid Build Coastguard Worker	}
266*333d2b36SAndroid Build Coastguard Worker	if l.mergedManifest != nil {
267*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
268*333d2b36SAndroid Build Coastguard Worker	}
269*333d2b36SAndroid Build Coastguard Worker
270*333d2b36SAndroid Build Coastguard Worker	// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
271*333d2b36SAndroid Build Coastguard Worker	// lint separately.
272*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithInput("--srcs ", srcsList)
273*333d2b36SAndroid Build Coastguard Worker
274*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithInput("--generated_srcs ", srcJarList)
275*333d2b36SAndroid Build Coastguard Worker
276*333d2b36SAndroid Build Coastguard Worker	if len(l.resources) > 0 {
277*333d2b36SAndroid Build Coastguard Worker		resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
278*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
279*333d2b36SAndroid Build Coastguard Worker	}
280*333d2b36SAndroid Build Coastguard Worker
281*333d2b36SAndroid Build Coastguard Worker	if l.classes != nil {
282*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithInput("--classes ", l.classes)
283*333d2b36SAndroid Build Coastguard Worker	}
284*333d2b36SAndroid Build Coastguard Worker
285*333d2b36SAndroid Build Coastguard Worker	cmd.FlagForEachInput("--classpath ", l.classpath)
286*333d2b36SAndroid Build Coastguard Worker
287*333d2b36SAndroid Build Coastguard Worker	cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
288*333d2b36SAndroid Build Coastguard Worker
289*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithArg("--root_dir ", "$PWD")
290*333d2b36SAndroid Build Coastguard Worker
291*333d2b36SAndroid Build Coastguard Worker	// The cache tag in project.xml is relative to the root dir, or the project.xml file if
292*333d2b36SAndroid Build Coastguard Worker	// the root dir is not set.
293*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithArg("--cache_dir ", cacheDir.String())
294*333d2b36SAndroid Build Coastguard Worker
295*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithInput("@",
296*333d2b36SAndroid Build Coastguard Worker		android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
297*333d2b36SAndroid Build Coastguard Worker
298*333d2b36SAndroid Build Coastguard Worker	cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
299*333d2b36SAndroid Build Coastguard Worker	cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
300*333d2b36SAndroid Build Coastguard Worker	cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
301*333d2b36SAndroid Build Coastguard Worker	cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
302*333d2b36SAndroid Build Coastguard Worker	cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
303*333d2b36SAndroid Build Coastguard Worker
304*333d2b36SAndroid Build Coastguard Worker	if Bool(l.properties.Lint.Strict_updatability_linting) && len(baselines) > 0 {
305*333d2b36SAndroid Build Coastguard Worker		// Verify the module does not baseline issues that endanger safe updatability.
306*333d2b36SAndroid Build Coastguard Worker		strictUpdatabilityChecksOutputFile := VerifyStrictUpdatabilityChecks(ctx, baselines)
307*333d2b36SAndroid Build Coastguard Worker		cmd.Validation(strictUpdatabilityChecksOutputFile)
308*333d2b36SAndroid Build Coastguard Worker	}
309*333d2b36SAndroid Build Coastguard Worker
310*333d2b36SAndroid Build Coastguard Worker	return lintPaths{
311*333d2b36SAndroid Build Coastguard Worker		projectXML: projectXMLPath,
312*333d2b36SAndroid Build Coastguard Worker		configXML:  configXMLPath,
313*333d2b36SAndroid Build Coastguard Worker		cacheDir:   cacheDir,
314*333d2b36SAndroid Build Coastguard Worker		homeDir:    homeDir,
315*333d2b36SAndroid Build Coastguard Worker	}
316*333d2b36SAndroid Build Coastguard Worker
317*333d2b36SAndroid Build Coastguard Worker}
318*333d2b36SAndroid Build Coastguard Worker
319*333d2b36SAndroid Build Coastguard Workerfunc VerifyStrictUpdatabilityChecks(ctx android.ModuleContext, baselines android.Paths) android.Path {
320*333d2b36SAndroid Build Coastguard Worker	rule := android.NewRuleBuilder(pctx, ctx)
321*333d2b36SAndroid Build Coastguard Worker	baselineRspFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check_baselines.rsp")
322*333d2b36SAndroid Build Coastguard Worker	outputFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check.stamp")
323*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("rm -f").Output(outputFile)
324*333d2b36SAndroid Build Coastguard Worker	rule.Command().
325*333d2b36SAndroid Build Coastguard Worker		BuiltTool("lint_strict_updatability_checks").
326*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--name ", ctx.ModuleName()).
327*333d2b36SAndroid Build Coastguard Worker		FlagWithRspFileInputList("--baselines ", baselineRspFile, baselines).
328*333d2b36SAndroid Build Coastguard Worker		FlagForEachArg("--disallowed_issues ", updatabilityChecks)
329*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("touch").Output(outputFile)
330*333d2b36SAndroid Build Coastguard Worker	rule.Build("lint_strict_updatability_checks", "lint strict updatability checks")
331*333d2b36SAndroid Build Coastguard Worker
332*333d2b36SAndroid Build Coastguard Worker	return outputFile
333*333d2b36SAndroid Build Coastguard Worker}
334*333d2b36SAndroid Build Coastguard Worker
335*333d2b36SAndroid Build Coastguard Worker// generateManifest adds a command to the rule to write a simple manifest that contains the
336*333d2b36SAndroid Build Coastguard Worker// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
337*333d2b36SAndroid Build Coastguard Workerfunc (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
338*333d2b36SAndroid Build Coastguard Worker	manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
339*333d2b36SAndroid Build Coastguard Worker
340*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("(").
341*333d2b36SAndroid Build Coastguard Worker		Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
342*333d2b36SAndroid Build Coastguard Worker		Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
343*333d2b36SAndroid Build Coastguard Worker		Text(`echo "    android:versionCode='1' android:versionName='1' >" &&`).
344*333d2b36SAndroid Build Coastguard Worker		Textf(`echo "  <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
345*333d2b36SAndroid Build Coastguard Worker			l.minSdkVersion.String(), l.targetSdkVersion.String()).
346*333d2b36SAndroid Build Coastguard Worker		Text(`echo "</manifest>"`).
347*333d2b36SAndroid Build Coastguard Worker		Text(") >").Output(manifestPath)
348*333d2b36SAndroid Build Coastguard Worker
349*333d2b36SAndroid Build Coastguard Worker	return manifestPath
350*333d2b36SAndroid Build Coastguard Worker}
351*333d2b36SAndroid Build Coastguard Worker
352*333d2b36SAndroid Build Coastguard Workerfunc (l *linter) lint(ctx android.ModuleContext) {
353*333d2b36SAndroid Build Coastguard Worker	if !l.enabled() {
354*333d2b36SAndroid Build Coastguard Worker		return
355*333d2b36SAndroid Build Coastguard Worker	}
356*333d2b36SAndroid Build Coastguard Worker
357*333d2b36SAndroid Build Coastguard Worker	for _, flag := range l.properties.Lint.Flags {
358*333d2b36SAndroid Build Coastguard Worker		if strings.Contains(flag, "--disable") || strings.Contains(flag, "--enable") || strings.Contains(flag, "--check") {
359*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("lint.flags", "Don't use --disable, --enable, or --check in the flags field, instead use the dedicated disabled_checks, warning_checks, error_checks, or fatal_checks fields")
360*333d2b36SAndroid Build Coastguard Worker		}
361*333d2b36SAndroid Build Coastguard Worker	}
362*333d2b36SAndroid Build Coastguard Worker
363*333d2b36SAndroid Build Coastguard Worker	if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
364*333d2b36SAndroid Build Coastguard Worker		l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
365*333d2b36SAndroid Build Coastguard Worker		// Skip lint warning checks for NewApi warnings for libcore where they come from source
366*333d2b36SAndroid Build Coastguard Worker		// files that reference the API they are adding (b/208656169).
367*333d2b36SAndroid Build Coastguard Worker		if !strings.HasPrefix(ctx.ModuleDir(), "libcore") {
368*333d2b36SAndroid Build Coastguard Worker			_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
369*333d2b36SAndroid Build Coastguard Worker
370*333d2b36SAndroid Build Coastguard Worker			if len(filtered) != 0 {
371*333d2b36SAndroid Build Coastguard Worker				ctx.PropertyErrorf("lint.warning_checks",
372*333d2b36SAndroid Build Coastguard Worker					"Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
373*333d2b36SAndroid Build Coastguard Worker			}
374*333d2b36SAndroid Build Coastguard Worker		}
375*333d2b36SAndroid Build Coastguard Worker
376*333d2b36SAndroid Build Coastguard Worker		_, filtered := android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
377*333d2b36SAndroid Build Coastguard Worker		if len(filtered) != 0 {
378*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("lint.disabled_checks",
379*333d2b36SAndroid Build Coastguard Worker				"Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
380*333d2b36SAndroid Build Coastguard Worker		}
381*333d2b36SAndroid Build Coastguard Worker
382*333d2b36SAndroid Build Coastguard Worker		// TODO(b/238784089): Remove this workaround when the NewApi issues have been addressed in PermissionController
383*333d2b36SAndroid Build Coastguard Worker		if ctx.ModuleName() == "PermissionController" {
384*333d2b36SAndroid Build Coastguard Worker			l.extraMainlineLintErrors = android.FilterListPred(l.extraMainlineLintErrors, func(s string) bool {
385*333d2b36SAndroid Build Coastguard Worker				return s != "NewApi"
386*333d2b36SAndroid Build Coastguard Worker			})
387*333d2b36SAndroid Build Coastguard Worker			l.properties.Lint.Warning_checks = append(l.properties.Lint.Warning_checks, "NewApi")
388*333d2b36SAndroid Build Coastguard Worker		}
389*333d2b36SAndroid Build Coastguard Worker	}
390*333d2b36SAndroid Build Coastguard Worker
391*333d2b36SAndroid Build Coastguard Worker	extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
392*333d2b36SAndroid Build Coastguard Worker	for _, extraLintCheckModule := range extraLintCheckModules {
393*333d2b36SAndroid Build Coastguard Worker		if dep, ok := android.OtherModuleProvider(ctx, extraLintCheckModule, JavaInfoProvider); ok {
394*333d2b36SAndroid Build Coastguard Worker			l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
395*333d2b36SAndroid Build Coastguard Worker		} else {
396*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("lint.extra_check_modules",
397*333d2b36SAndroid Build Coastguard Worker				"%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
398*333d2b36SAndroid Build Coastguard Worker		}
399*333d2b36SAndroid Build Coastguard Worker	}
400*333d2b36SAndroid Build Coastguard Worker
401*333d2b36SAndroid Build Coastguard Worker	l.extraLintCheckJars = append(l.extraLintCheckJars, android.PathForSource(ctx,
402*333d2b36SAndroid Build Coastguard Worker		"prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar"))
403*333d2b36SAndroid Build Coastguard Worker
404*333d2b36SAndroid Build Coastguard Worker	var baseline android.OptionalPath
405*333d2b36SAndroid Build Coastguard Worker	if l.properties.Lint.Baseline_filename != nil {
406*333d2b36SAndroid Build Coastguard Worker		baseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
407*333d2b36SAndroid Build Coastguard Worker	}
408*333d2b36SAndroid Build Coastguard Worker
409*333d2b36SAndroid Build Coastguard Worker	html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
410*333d2b36SAndroid Build Coastguard Worker	text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
411*333d2b36SAndroid Build Coastguard Worker	xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
412*333d2b36SAndroid Build Coastguard Worker	referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
413*333d2b36SAndroid Build Coastguard Worker
414*333d2b36SAndroid Build Coastguard Worker	depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml, baseline)
415*333d2b36SAndroid Build Coastguard Worker
416*333d2b36SAndroid Build Coastguard Worker	ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
417*333d2b36SAndroid Build Coastguard Worker		if info, ok := android.OtherModuleProvider(ctx, dep, LintProvider); ok {
418*333d2b36SAndroid Build Coastguard Worker			depSetsBuilder.Transitive(info)
419*333d2b36SAndroid Build Coastguard Worker		}
420*333d2b36SAndroid Build Coastguard Worker	})
421*333d2b36SAndroid Build Coastguard Worker
422*333d2b36SAndroid Build Coastguard Worker	depSets := depSetsBuilder.Build()
423*333d2b36SAndroid Build Coastguard Worker
424*333d2b36SAndroid Build Coastguard Worker	rule := android.NewRuleBuilder(pctx, ctx).
425*333d2b36SAndroid Build Coastguard Worker		Sbox(android.PathForModuleOut(ctx, "lint"),
426*333d2b36SAndroid Build Coastguard Worker			android.PathForModuleOut(ctx, "lint.sbox.textproto")).
427*333d2b36SAndroid Build Coastguard Worker		SandboxInputs()
428*333d2b36SAndroid Build Coastguard Worker
429*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
430*333d2b36SAndroid Build Coastguard Worker		pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
431*333d2b36SAndroid Build Coastguard Worker		rule.Remoteable(android.RemoteRuleSupports{RBE: true})
432*333d2b36SAndroid Build Coastguard Worker		rule.Rewrapper(&remoteexec.REParams{
433*333d2b36SAndroid Build Coastguard Worker			Labels:          map[string]string{"type": "tool", "name": "lint"},
434*333d2b36SAndroid Build Coastguard Worker			ExecStrategy:    lintRBEExecStrategy(ctx),
435*333d2b36SAndroid Build Coastguard Worker			ToolchainInputs: []string{config.JavaCmd(ctx).String()},
436*333d2b36SAndroid Build Coastguard Worker			Platform:        map[string]string{remoteexec.PoolKey: pool},
437*333d2b36SAndroid Build Coastguard Worker		})
438*333d2b36SAndroid Build Coastguard Worker	}
439*333d2b36SAndroid Build Coastguard Worker
440*333d2b36SAndroid Build Coastguard Worker	if l.manifest == nil {
441*333d2b36SAndroid Build Coastguard Worker		manifest := l.generateManifest(ctx, rule)
442*333d2b36SAndroid Build Coastguard Worker		l.manifest = manifest
443*333d2b36SAndroid Build Coastguard Worker		rule.Temporary(manifest)
444*333d2b36SAndroid Build Coastguard Worker	}
445*333d2b36SAndroid Build Coastguard Worker
446*333d2b36SAndroid Build Coastguard Worker	srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
447*333d2b36SAndroid Build Coastguard Worker	srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
448*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList).Implicits(l.compile_data)
449*333d2b36SAndroid Build Coastguard Worker
450*333d2b36SAndroid Build Coastguard Worker	baselines := depSets.Baseline.ToList()
451*333d2b36SAndroid Build Coastguard Worker
452*333d2b36SAndroid Build Coastguard Worker	lintPaths := l.writeLintProjectXML(ctx, rule, srcsList, baselines)
453*333d2b36SAndroid Build Coastguard Worker
454*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
455*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
456*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
457*333d2b36SAndroid Build Coastguard Worker
458*333d2b36SAndroid Build Coastguard Worker	files, ok := allLintDatabasefiles[l.compileSdkKind]
459*333d2b36SAndroid Build Coastguard Worker	if !ok {
460*333d2b36SAndroid Build Coastguard Worker		files = allLintDatabasefiles[android.SdkPublic]
461*333d2b36SAndroid Build Coastguard Worker	}
462*333d2b36SAndroid Build Coastguard Worker	var annotationsZipPath, apiVersionsXMLPath android.Path
463*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().AlwaysUsePrebuiltSdks() {
464*333d2b36SAndroid Build Coastguard Worker		annotationsZipPath = android.PathForSource(ctx, files.annotationPrebuiltpath)
465*333d2b36SAndroid Build Coastguard Worker		apiVersionsXMLPath = android.PathForSource(ctx, files.apiVersionsPrebuiltPath)
466*333d2b36SAndroid Build Coastguard Worker	} else {
467*333d2b36SAndroid Build Coastguard Worker		annotationsZipPath = copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName)
468*333d2b36SAndroid Build Coastguard Worker		apiVersionsXMLPath = copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName)
469*333d2b36SAndroid Build Coastguard Worker	}
470*333d2b36SAndroid Build Coastguard Worker
471*333d2b36SAndroid Build Coastguard Worker	cmd := rule.Command()
472*333d2b36SAndroid Build Coastguard Worker
473*333d2b36SAndroid Build Coastguard Worker	cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
474*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
475*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
476*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
477*333d2b36SAndroid Build Coastguard Worker
478*333d2b36SAndroid Build Coastguard Worker	cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
479*333d2b36SAndroid Build Coastguard Worker		Flag("--quiet").
480*333d2b36SAndroid Build Coastguard Worker		Flag("--include-aosp-issues").
481*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("--project ", lintPaths.projectXML).
482*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("--config ", lintPaths.configXML).
483*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--html ", html).
484*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--text ", text).
485*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("--xml ", xml).
486*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
487*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--java-language-level ", l.javaLanguageLevel).
488*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
489*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
490*333d2b36SAndroid Build Coastguard Worker		Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
491*333d2b36SAndroid Build Coastguard Worker		Flags(l.properties.Lint.Flags).
492*333d2b36SAndroid Build Coastguard Worker		Implicit(annotationsZipPath).
493*333d2b36SAndroid Build Coastguard Worker		Implicit(apiVersionsXMLPath)
494*333d2b36SAndroid Build Coastguard Worker
495*333d2b36SAndroid Build Coastguard Worker	rule.Temporary(lintPaths.projectXML)
496*333d2b36SAndroid Build Coastguard Worker	rule.Temporary(lintPaths.configXML)
497*333d2b36SAndroid Build Coastguard Worker
498*333d2b36SAndroid Build Coastguard Worker	suppressExitCode := BoolDefault(l.properties.Lint.Suppress_exit_code, false)
499*333d2b36SAndroid Build Coastguard Worker	if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" && !suppressExitCode {
500*333d2b36SAndroid Build Coastguard Worker		cmd.Flag("--exitcode")
501*333d2b36SAndroid Build Coastguard Worker	}
502*333d2b36SAndroid Build Coastguard Worker
503*333d2b36SAndroid Build Coastguard Worker	if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
504*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithArg("--check ", checkOnly)
505*333d2b36SAndroid Build Coastguard Worker	}
506*333d2b36SAndroid Build Coastguard Worker
507*333d2b36SAndroid Build Coastguard Worker	if baseline.Valid() {
508*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithInput("--baseline ", baseline.Path())
509*333d2b36SAndroid Build Coastguard Worker	}
510*333d2b36SAndroid Build Coastguard Worker
511*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
512*333d2b36SAndroid Build Coastguard Worker
513*333d2b36SAndroid Build Coastguard Worker	cmd.Text("; EXITCODE=$?; ")
514*333d2b36SAndroid Build Coastguard Worker
515*333d2b36SAndroid Build Coastguard Worker	// The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
516*333d2b36SAndroid Build Coastguard Worker	// export them out of the sandbox.  Do this before exiting so that the suggestions exit even after
517*333d2b36SAndroid Build Coastguard Worker	// a fatal error.
518*333d2b36SAndroid Build Coastguard Worker	cmd.BuiltTool("soong_zip").
519*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
520*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
521*333d2b36SAndroid Build Coastguard Worker		FlagWithInput("-r ", srcsList)
522*333d2b36SAndroid Build Coastguard Worker
523*333d2b36SAndroid Build Coastguard Worker	cmd.Text("; if [ $EXITCODE != 0 ]; then if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit $EXITCODE; fi")
524*333d2b36SAndroid Build Coastguard Worker
525*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
526*333d2b36SAndroid Build Coastguard Worker
527*333d2b36SAndroid Build Coastguard Worker	// The HTML output contains a date, remove it to make the output deterministic.
528*333d2b36SAndroid Build Coastguard Worker	rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
529*333d2b36SAndroid Build Coastguard Worker
530*333d2b36SAndroid Build Coastguard Worker	rule.Build("lint", "lint")
531*333d2b36SAndroid Build Coastguard Worker
532*333d2b36SAndroid Build Coastguard Worker	android.SetProvider(ctx, LintProvider, &LintInfo{
533*333d2b36SAndroid Build Coastguard Worker		HTML:              html,
534*333d2b36SAndroid Build Coastguard Worker		Text:              text,
535*333d2b36SAndroid Build Coastguard Worker		XML:               xml,
536*333d2b36SAndroid Build Coastguard Worker		ReferenceBaseline: referenceBaseline,
537*333d2b36SAndroid Build Coastguard Worker
538*333d2b36SAndroid Build Coastguard Worker		TransitiveHTML:     depSets.HTML,
539*333d2b36SAndroid Build Coastguard Worker		TransitiveText:     depSets.Text,
540*333d2b36SAndroid Build Coastguard Worker		TransitiveXML:      depSets.XML,
541*333d2b36SAndroid Build Coastguard Worker		TransitiveBaseline: depSets.Baseline,
542*333d2b36SAndroid Build Coastguard Worker	})
543*333d2b36SAndroid Build Coastguard Worker
544*333d2b36SAndroid Build Coastguard Worker	if l.buildModuleReportZip {
545*333d2b36SAndroid Build Coastguard Worker		l.reports = BuildModuleLintReportZips(ctx, depSets, nil)
546*333d2b36SAndroid Build Coastguard Worker	}
547*333d2b36SAndroid Build Coastguard Worker
548*333d2b36SAndroid Build Coastguard Worker	// Create a per-module phony target to run the lint check.
549*333d2b36SAndroid Build Coastguard Worker	phonyName := ctx.ModuleName() + "-lint"
550*333d2b36SAndroid Build Coastguard Worker	ctx.Phony(phonyName, xml)
551*333d2b36SAndroid Build Coastguard Worker
552*333d2b36SAndroid Build Coastguard Worker	ctx.SetOutputFiles(android.Paths{xml}, ".lint")
553*333d2b36SAndroid Build Coastguard Worker}
554*333d2b36SAndroid Build Coastguard Worker
555*333d2b36SAndroid Build Coastguard Workerfunc BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets, validations android.Paths) android.Paths {
556*333d2b36SAndroid Build Coastguard Worker	htmlList := android.SortedUniquePaths(depSets.HTML.ToList())
557*333d2b36SAndroid Build Coastguard Worker	textList := android.SortedUniquePaths(depSets.Text.ToList())
558*333d2b36SAndroid Build Coastguard Worker	xmlList := android.SortedUniquePaths(depSets.XML.ToList())
559*333d2b36SAndroid Build Coastguard Worker
560*333d2b36SAndroid Build Coastguard Worker	if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
561*333d2b36SAndroid Build Coastguard Worker		return nil
562*333d2b36SAndroid Build Coastguard Worker	}
563*333d2b36SAndroid Build Coastguard Worker
564*333d2b36SAndroid Build Coastguard Worker	htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
565*333d2b36SAndroid Build Coastguard Worker	lintZip(ctx, htmlList, htmlZip, validations)
566*333d2b36SAndroid Build Coastguard Worker
567*333d2b36SAndroid Build Coastguard Worker	textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
568*333d2b36SAndroid Build Coastguard Worker	lintZip(ctx, textList, textZip, validations)
569*333d2b36SAndroid Build Coastguard Worker
570*333d2b36SAndroid Build Coastguard Worker	xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
571*333d2b36SAndroid Build Coastguard Worker	lintZip(ctx, xmlList, xmlZip, validations)
572*333d2b36SAndroid Build Coastguard Worker
573*333d2b36SAndroid Build Coastguard Worker	return android.Paths{htmlZip, textZip, xmlZip}
574*333d2b36SAndroid Build Coastguard Worker}
575*333d2b36SAndroid Build Coastguard Worker
576*333d2b36SAndroid Build Coastguard Workertype lintSingleton struct {
577*333d2b36SAndroid Build Coastguard Worker	htmlZip              android.WritablePath
578*333d2b36SAndroid Build Coastguard Worker	textZip              android.WritablePath
579*333d2b36SAndroid Build Coastguard Worker	xmlZip               android.WritablePath
580*333d2b36SAndroid Build Coastguard Worker	referenceBaselineZip android.WritablePath
581*333d2b36SAndroid Build Coastguard Worker}
582*333d2b36SAndroid Build Coastguard Worker
583*333d2b36SAndroid Build Coastguard Workerfunc (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
584*333d2b36SAndroid Build Coastguard Worker	l.generateLintReportZips(ctx)
585*333d2b36SAndroid Build Coastguard Worker	l.copyLintDependencies(ctx)
586*333d2b36SAndroid Build Coastguard Worker}
587*333d2b36SAndroid Build Coastguard Worker
588*333d2b36SAndroid Build Coastguard Workerfunc findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
589*333d2b36SAndroid Build Coastguard Worker	var res android.Module
590*333d2b36SAndroid Build Coastguard Worker	ctx.VisitAllModules(func(m android.Module) {
591*333d2b36SAndroid Build Coastguard Worker		if ctx.ModuleName(m) == moduleName {
592*333d2b36SAndroid Build Coastguard Worker			if res == nil {
593*333d2b36SAndroid Build Coastguard Worker				res = m
594*333d2b36SAndroid Build Coastguard Worker			} else {
595*333d2b36SAndroid Build Coastguard Worker				ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
596*333d2b36SAndroid Build Coastguard Worker					ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
597*333d2b36SAndroid Build Coastguard Worker			}
598*333d2b36SAndroid Build Coastguard Worker		}
599*333d2b36SAndroid Build Coastguard Worker	})
600*333d2b36SAndroid Build Coastguard Worker	return res
601*333d2b36SAndroid Build Coastguard Worker}
602*333d2b36SAndroid Build Coastguard Worker
603*333d2b36SAndroid Build Coastguard Workerfunc (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
604*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().AlwaysUsePrebuiltSdks() {
605*333d2b36SAndroid Build Coastguard Worker		return
606*333d2b36SAndroid Build Coastguard Worker	}
607*333d2b36SAndroid Build Coastguard Worker
608*333d2b36SAndroid Build Coastguard Worker	for _, sdk := range android.SortedKeys(allLintDatabasefiles) {
609*333d2b36SAndroid Build Coastguard Worker		files := allLintDatabasefiles[sdk]
610*333d2b36SAndroid Build Coastguard Worker		apiVersionsDb := findModuleOrErr(ctx, files.apiVersionsModule)
611*333d2b36SAndroid Build Coastguard Worker		if apiVersionsDb == nil {
612*333d2b36SAndroid Build Coastguard Worker			if !ctx.Config().AllowMissingDependencies() {
613*333d2b36SAndroid Build Coastguard Worker				ctx.Errorf("lint: missing module %s", files.apiVersionsModule)
614*333d2b36SAndroid Build Coastguard Worker			}
615*333d2b36SAndroid Build Coastguard Worker			return
616*333d2b36SAndroid Build Coastguard Worker		}
617*333d2b36SAndroid Build Coastguard Worker
618*333d2b36SAndroid Build Coastguard Worker		sdkAnnotations := findModuleOrErr(ctx, files.annotationsModule)
619*333d2b36SAndroid Build Coastguard Worker		if sdkAnnotations == nil {
620*333d2b36SAndroid Build Coastguard Worker			if !ctx.Config().AllowMissingDependencies() {
621*333d2b36SAndroid Build Coastguard Worker				ctx.Errorf("lint: missing module %s", files.annotationsModule)
622*333d2b36SAndroid Build Coastguard Worker			}
623*333d2b36SAndroid Build Coastguard Worker			return
624*333d2b36SAndroid Build Coastguard Worker		}
625*333d2b36SAndroid Build Coastguard Worker
626*333d2b36SAndroid Build Coastguard Worker		ctx.Build(pctx, android.BuildParams{
627*333d2b36SAndroid Build Coastguard Worker			Rule:   android.CpIfChanged,
628*333d2b36SAndroid Build Coastguard Worker			Input:  android.OutputFileForModule(ctx, sdkAnnotations, ""),
629*333d2b36SAndroid Build Coastguard Worker			Output: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
630*333d2b36SAndroid Build Coastguard Worker		})
631*333d2b36SAndroid Build Coastguard Worker
632*333d2b36SAndroid Build Coastguard Worker		ctx.Build(pctx, android.BuildParams{
633*333d2b36SAndroid Build Coastguard Worker			Rule:   android.CpIfChanged,
634*333d2b36SAndroid Build Coastguard Worker			Input:  android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
635*333d2b36SAndroid Build Coastguard Worker			Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
636*333d2b36SAndroid Build Coastguard Worker		})
637*333d2b36SAndroid Build Coastguard Worker	}
638*333d2b36SAndroid Build Coastguard Worker}
639*333d2b36SAndroid Build Coastguard Worker
640*333d2b36SAndroid Build Coastguard Workerfunc copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.WritablePath {
641*333d2b36SAndroid Build Coastguard Worker	return android.PathForOutput(ctx, "lint", name)
642*333d2b36SAndroid Build Coastguard Worker}
643*333d2b36SAndroid Build Coastguard Worker
644*333d2b36SAndroid Build Coastguard Workerfunc (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
645*333d2b36SAndroid Build Coastguard Worker	if ctx.Config().UnbundledBuild() {
646*333d2b36SAndroid Build Coastguard Worker		return
647*333d2b36SAndroid Build Coastguard Worker	}
648*333d2b36SAndroid Build Coastguard Worker
649*333d2b36SAndroid Build Coastguard Worker	var outputs []*LintInfo
650*333d2b36SAndroid Build Coastguard Worker	var dirs []string
651*333d2b36SAndroid Build Coastguard Worker	ctx.VisitAllModules(func(m android.Module) {
652*333d2b36SAndroid Build Coastguard Worker		if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
653*333d2b36SAndroid Build Coastguard Worker			return
654*333d2b36SAndroid Build Coastguard Worker		}
655*333d2b36SAndroid Build Coastguard Worker
656*333d2b36SAndroid Build Coastguard Worker		if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
657*333d2b36SAndroid Build Coastguard Worker			apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
658*333d2b36SAndroid Build Coastguard Worker			if apexInfo.IsForPlatform() {
659*333d2b36SAndroid Build Coastguard Worker				// There are stray platform variants of modules in apexes that are not available for
660*333d2b36SAndroid Build Coastguard Worker				// the platform, and they sometimes can't be built.  Don't depend on them.
661*333d2b36SAndroid Build Coastguard Worker				return
662*333d2b36SAndroid Build Coastguard Worker			}
663*333d2b36SAndroid Build Coastguard Worker		}
664*333d2b36SAndroid Build Coastguard Worker
665*333d2b36SAndroid Build Coastguard Worker		if lintInfo, ok := android.OtherModuleProvider(ctx, m, LintProvider); ok {
666*333d2b36SAndroid Build Coastguard Worker			outputs = append(outputs, lintInfo)
667*333d2b36SAndroid Build Coastguard Worker		}
668*333d2b36SAndroid Build Coastguard Worker	})
669*333d2b36SAndroid Build Coastguard Worker
670*333d2b36SAndroid Build Coastguard Worker	dirs = android.SortedUniqueStrings(dirs)
671*333d2b36SAndroid Build Coastguard Worker
672*333d2b36SAndroid Build Coastguard Worker	zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) {
673*333d2b36SAndroid Build Coastguard Worker		var paths android.Paths
674*333d2b36SAndroid Build Coastguard Worker
675*333d2b36SAndroid Build Coastguard Worker		for _, output := range outputs {
676*333d2b36SAndroid Build Coastguard Worker			if p := get(output); p != nil {
677*333d2b36SAndroid Build Coastguard Worker				paths = append(paths, p)
678*333d2b36SAndroid Build Coastguard Worker			}
679*333d2b36SAndroid Build Coastguard Worker		}
680*333d2b36SAndroid Build Coastguard Worker
681*333d2b36SAndroid Build Coastguard Worker		lintZip(ctx, paths, outputPath, nil)
682*333d2b36SAndroid Build Coastguard Worker	}
683*333d2b36SAndroid Build Coastguard Worker
684*333d2b36SAndroid Build Coastguard Worker	l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
685*333d2b36SAndroid Build Coastguard Worker	zip(l.htmlZip, func(l *LintInfo) android.Path { return l.HTML })
686*333d2b36SAndroid Build Coastguard Worker
687*333d2b36SAndroid Build Coastguard Worker	l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
688*333d2b36SAndroid Build Coastguard Worker	zip(l.textZip, func(l *LintInfo) android.Path { return l.Text })
689*333d2b36SAndroid Build Coastguard Worker
690*333d2b36SAndroid Build Coastguard Worker	l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
691*333d2b36SAndroid Build Coastguard Worker	zip(l.xmlZip, func(l *LintInfo) android.Path { return l.XML })
692*333d2b36SAndroid Build Coastguard Worker
693*333d2b36SAndroid Build Coastguard Worker	l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip")
694*333d2b36SAndroid Build Coastguard Worker	zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline })
695*333d2b36SAndroid Build Coastguard Worker
696*333d2b36SAndroid Build Coastguard Worker	ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
697*333d2b36SAndroid Build Coastguard Worker}
698*333d2b36SAndroid Build Coastguard Worker
699*333d2b36SAndroid Build Coastguard Workerfunc (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
700*333d2b36SAndroid Build Coastguard Worker	if !ctx.Config().UnbundledBuild() {
701*333d2b36SAndroid Build Coastguard Worker		ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip)
702*333d2b36SAndroid Build Coastguard Worker	}
703*333d2b36SAndroid Build Coastguard Worker}
704*333d2b36SAndroid Build Coastguard Worker
705*333d2b36SAndroid Build Coastguard Workervar _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
706*333d2b36SAndroid Build Coastguard Worker
707*333d2b36SAndroid Build Coastguard Workerfunc init() {
708*333d2b36SAndroid Build Coastguard Worker	android.RegisterParallelSingletonType("lint",
709*333d2b36SAndroid Build Coastguard Worker		func() android.Singleton { return &lintSingleton{} })
710*333d2b36SAndroid Build Coastguard Worker}
711*333d2b36SAndroid Build Coastguard Worker
712*333d2b36SAndroid Build Coastguard Workerfunc lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath, validations android.Paths) {
713*333d2b36SAndroid Build Coastguard Worker	paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
714*333d2b36SAndroid Build Coastguard Worker
715*333d2b36SAndroid Build Coastguard Worker	sort.Slice(paths, func(i, j int) bool {
716*333d2b36SAndroid Build Coastguard Worker		return paths[i].String() < paths[j].String()
717*333d2b36SAndroid Build Coastguard Worker	})
718*333d2b36SAndroid Build Coastguard Worker
719*333d2b36SAndroid Build Coastguard Worker	rule := android.NewRuleBuilder(pctx, ctx)
720*333d2b36SAndroid Build Coastguard Worker
721*333d2b36SAndroid Build Coastguard Worker	rule.Command().BuiltTool("soong_zip").
722*333d2b36SAndroid Build Coastguard Worker		FlagWithOutput("-o ", outputPath).
723*333d2b36SAndroid Build Coastguard Worker		FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
724*333d2b36SAndroid Build Coastguard Worker		FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths).
725*333d2b36SAndroid Build Coastguard Worker		Validations(validations)
726*333d2b36SAndroid Build Coastguard Worker
727*333d2b36SAndroid Build Coastguard Worker	rule.Build(outputPath.Base(), outputPath.Base())
728*333d2b36SAndroid Build Coastguard Worker}
729