lint.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. // 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. package java
  15. import (
  16. "fmt"
  17. "sort"
  18. "strings"
  19. "github.com/google/blueprint/proptools"
  20. "android/soong/android"
  21. "android/soong/java/config"
  22. "android/soong/remoteexec"
  23. )
  24. // lint checks automatically enforced for modules that have different min_sdk_version than
  25. // sdk_version
  26. var updatabilityChecks = []string{"NewApi"}
  27. type LintProperties struct {
  28. // Controls for running Android Lint on the module.
  29. Lint struct {
  30. // If true, run Android Lint on the module. Defaults to true.
  31. Enabled *bool
  32. // Flags to pass to the Android Lint tool.
  33. Flags []string
  34. // Checks that should be treated as fatal.
  35. Fatal_checks []string
  36. // Checks that should be treated as errors.
  37. Error_checks []string
  38. // Checks that should be treated as warnings.
  39. Warning_checks []string
  40. // Checks that should be skipped.
  41. Disabled_checks []string
  42. // Modules that provide extra lint checks
  43. Extra_check_modules []string
  44. // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
  45. Baseline_filename *string
  46. // If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
  47. Strict_updatability_linting *bool
  48. }
  49. }
  50. type linter struct {
  51. name string
  52. manifest android.Path
  53. mergedManifest android.Path
  54. srcs android.Paths
  55. srcJars android.Paths
  56. resources android.Paths
  57. classpath android.Paths
  58. classes android.Path
  59. extraLintCheckJars android.Paths
  60. test bool
  61. library bool
  62. minSdkVersion string
  63. targetSdkVersion string
  64. compileSdkVersion string
  65. javaLanguageLevel string
  66. kotlinLanguageLevel string
  67. outputs lintOutputs
  68. properties LintProperties
  69. extraMainlineLintErrors []string
  70. reports android.Paths
  71. buildModuleReportZip bool
  72. }
  73. type lintOutputs struct {
  74. html android.Path
  75. text android.Path
  76. xml android.Path
  77. depSets LintDepSets
  78. }
  79. type lintOutputsIntf interface {
  80. lintOutputs() *lintOutputs
  81. }
  82. type lintDepSetsIntf interface {
  83. LintDepSets() LintDepSets
  84. // Methods used to propagate strict_updatability_linting values.
  85. getStrictUpdatabilityLinting() bool
  86. setStrictUpdatabilityLinting(bool)
  87. }
  88. type LintDepSets struct {
  89. HTML, Text, XML *android.DepSet
  90. }
  91. type LintDepSetsBuilder struct {
  92. HTML, Text, XML *android.DepSetBuilder
  93. }
  94. func NewLintDepSetBuilder() LintDepSetsBuilder {
  95. return LintDepSetsBuilder{
  96. HTML: android.NewDepSetBuilder(android.POSTORDER),
  97. Text: android.NewDepSetBuilder(android.POSTORDER),
  98. XML: android.NewDepSetBuilder(android.POSTORDER),
  99. }
  100. }
  101. func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
  102. l.HTML.Direct(html)
  103. l.Text.Direct(text)
  104. l.XML.Direct(xml)
  105. return l
  106. }
  107. func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
  108. if depSets.HTML != nil {
  109. l.HTML.Transitive(depSets.HTML)
  110. }
  111. if depSets.Text != nil {
  112. l.Text.Transitive(depSets.Text)
  113. }
  114. if depSets.XML != nil {
  115. l.XML.Transitive(depSets.XML)
  116. }
  117. return l
  118. }
  119. func (l LintDepSetsBuilder) Build() LintDepSets {
  120. return LintDepSets{
  121. HTML: l.HTML.Build(),
  122. Text: l.Text.Build(),
  123. XML: l.XML.Build(),
  124. }
  125. }
  126. func (l *linter) LintDepSets() LintDepSets {
  127. return l.outputs.depSets
  128. }
  129. func (l *linter) getStrictUpdatabilityLinting() bool {
  130. return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
  131. }
  132. func (l *linter) setStrictUpdatabilityLinting(strictLinting bool) {
  133. l.properties.Lint.Strict_updatability_linting = &strictLinting
  134. }
  135. var _ lintDepSetsIntf = (*linter)(nil)
  136. var _ lintOutputsIntf = (*linter)(nil)
  137. func (l *linter) lintOutputs() *lintOutputs {
  138. return &l.outputs
  139. }
  140. func (l *linter) enabled() bool {
  141. return BoolDefault(l.properties.Lint.Enabled, true)
  142. }
  143. func (l *linter) deps(ctx android.BottomUpMutatorContext) {
  144. if !l.enabled() {
  145. return
  146. }
  147. extraCheckModules := l.properties.Lint.Extra_check_modules
  148. if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
  149. if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
  150. extraCheckModules = strings.Split(checkOnlyModules, ",")
  151. }
  152. }
  153. ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
  154. extraLintCheckTag, extraCheckModules...)
  155. }
  156. // lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
  157. // around.
  158. type lintPaths struct {
  159. projectXML android.WritablePath
  160. configXML android.WritablePath
  161. cacheDir android.WritablePath
  162. homeDir android.WritablePath
  163. srcjarDir android.WritablePath
  164. }
  165. func lintRBEExecStrategy(ctx android.ModuleContext) string {
  166. return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
  167. }
  168. func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
  169. projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
  170. // Lint looks for a lint.xml file next to the project.xml file, give it one.
  171. configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
  172. cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
  173. homeDir := android.PathForModuleOut(ctx, "lint", "home")
  174. srcJarDir := android.PathForModuleOut(ctx, "lint", "srcjars")
  175. srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
  176. cmd := rule.Command().
  177. BuiltTool("lint_project_xml").
  178. FlagWithOutput("--project_out ", projectXMLPath).
  179. FlagWithOutput("--config_out ", configXMLPath).
  180. FlagWithArg("--name ", ctx.ModuleName())
  181. if l.library {
  182. cmd.Flag("--library")
  183. }
  184. if l.test {
  185. cmd.Flag("--test")
  186. }
  187. if l.manifest != nil {
  188. cmd.FlagWithInput("--manifest ", l.manifest)
  189. }
  190. if l.mergedManifest != nil {
  191. cmd.FlagWithInput("--merged_manifest ", l.mergedManifest)
  192. }
  193. // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
  194. // lint separately.
  195. srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
  196. cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
  197. cmd.FlagWithInput("--generated_srcs ", srcJarList)
  198. if len(l.resources) > 0 {
  199. resourcesList := android.PathForModuleOut(ctx, "lint-resources.list")
  200. cmd.FlagWithRspFileInputList("--resources ", resourcesList, l.resources)
  201. }
  202. if l.classes != nil {
  203. cmd.FlagWithInput("--classes ", l.classes)
  204. }
  205. cmd.FlagForEachInput("--classpath ", l.classpath)
  206. cmd.FlagForEachInput("--extra_checks_jar ", l.extraLintCheckJars)
  207. cmd.FlagWithArg("--root_dir ", "$PWD")
  208. // The cache tag in project.xml is relative to the root dir, or the project.xml file if
  209. // the root dir is not set.
  210. cmd.FlagWithArg("--cache_dir ", cacheDir.String())
  211. cmd.FlagWithInput("@",
  212. android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
  213. cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
  214. cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
  215. cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
  216. cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
  217. cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
  218. if l.getStrictUpdatabilityLinting() {
  219. // Verify the module does not baseline issues that endanger safe updatability.
  220. if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
  221. cmd.FlagWithInput("--baseline ", baselinePath.Path())
  222. cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
  223. }
  224. }
  225. return lintPaths{
  226. projectXML: projectXMLPath,
  227. configXML: configXMLPath,
  228. cacheDir: cacheDir,
  229. homeDir: homeDir,
  230. }
  231. }
  232. // generateManifest adds a command to the rule to write a simple manifest that contains the
  233. // minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
  234. func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath {
  235. manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
  236. rule.Command().Text("(").
  237. Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
  238. Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
  239. Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
  240. Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
  241. l.minSdkVersion, l.targetSdkVersion).
  242. Text(`echo "</manifest>"`).
  243. Text(") >").Output(manifestPath)
  244. return manifestPath
  245. }
  246. func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
  247. var lintBaseline android.OptionalPath
  248. if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
  249. if String(l.properties.Lint.Baseline_filename) != "" {
  250. // if manually specified, we require the file to exist
  251. lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
  252. } else {
  253. lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
  254. }
  255. }
  256. return lintBaseline
  257. }
  258. func (l *linter) lint(ctx android.ModuleContext) {
  259. if !l.enabled() {
  260. return
  261. }
  262. if l.minSdkVersion != l.compileSdkVersion {
  263. l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
  264. _, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
  265. if len(filtered) != 0 {
  266. ctx.PropertyErrorf("lint.warning_checks",
  267. "Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
  268. }
  269. _, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
  270. if len(filtered) != 0 {
  271. ctx.PropertyErrorf("lint.disabled_checks",
  272. "Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
  273. }
  274. }
  275. extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
  276. for _, extraLintCheckModule := range extraLintCheckModules {
  277. if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
  278. dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
  279. l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
  280. } else {
  281. ctx.PropertyErrorf("lint.extra_check_modules",
  282. "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
  283. }
  284. }
  285. rule := android.NewRuleBuilder(pctx, ctx).
  286. Sbox(android.PathForModuleOut(ctx, "lint"),
  287. android.PathForModuleOut(ctx, "lint.sbox.textproto")).
  288. SandboxInputs()
  289. if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
  290. pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
  291. rule.Remoteable(android.RemoteRuleSupports{RBE: true})
  292. rule.Rewrapper(&remoteexec.REParams{
  293. Labels: map[string]string{"type": "tool", "name": "lint"},
  294. ExecStrategy: lintRBEExecStrategy(ctx),
  295. ToolchainInputs: []string{config.JavaCmd(ctx).String()},
  296. Platform: map[string]string{remoteexec.PoolKey: pool},
  297. })
  298. }
  299. if l.manifest == nil {
  300. manifest := l.generateManifest(ctx, rule)
  301. l.manifest = manifest
  302. rule.Temporary(manifest)
  303. }
  304. lintPaths := l.writeLintProjectXML(ctx, rule)
  305. html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
  306. text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
  307. xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
  308. depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
  309. ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
  310. if depLint, ok := dep.(lintDepSetsIntf); ok {
  311. depSetsBuilder.Transitive(depLint.LintDepSets())
  312. }
  313. })
  314. rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
  315. rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
  316. rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
  317. var annotationsZipPath, apiVersionsXMLPath android.Path
  318. if ctx.Config().AlwaysUsePrebuiltSdks() {
  319. annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
  320. apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
  321. } else {
  322. annotationsZipPath = copiedAnnotationsZipPath(ctx)
  323. apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
  324. }
  325. cmd := rule.Command()
  326. cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`).
  327. FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
  328. FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
  329. FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
  330. cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
  331. Flag("--quiet").
  332. FlagWithInput("--project ", lintPaths.projectXML).
  333. FlagWithInput("--config ", lintPaths.configXML).
  334. FlagWithOutput("--html ", html).
  335. FlagWithOutput("--text ", text).
  336. FlagWithOutput("--xml ", xml).
  337. FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
  338. FlagWithArg("--java-language-level ", l.javaLanguageLevel).
  339. FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
  340. FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
  341. Flag("--exitcode").
  342. Flags(l.properties.Lint.Flags).
  343. Implicit(annotationsZipPath).
  344. Implicit(apiVersionsXMLPath)
  345. rule.Temporary(lintPaths.projectXML)
  346. rule.Temporary(lintPaths.configXML)
  347. if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
  348. cmd.FlagWithArg("--check ", checkOnly)
  349. }
  350. lintBaseline := l.getBaselineFilepath(ctx)
  351. if lintBaseline.Valid() {
  352. cmd.FlagWithInput("--baseline ", lintBaseline.Path())
  353. }
  354. cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
  355. rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
  356. // The HTML output contains a date, remove it to make the output deterministic.
  357. rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
  358. rule.Build("lint", "lint")
  359. l.outputs = lintOutputs{
  360. html: html,
  361. text: text,
  362. xml: xml,
  363. depSets: depSetsBuilder.Build(),
  364. }
  365. if l.buildModuleReportZip {
  366. l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
  367. }
  368. }
  369. func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
  370. htmlList := depSets.HTML.ToSortedList()
  371. textList := depSets.Text.ToSortedList()
  372. xmlList := depSets.XML.ToSortedList()
  373. if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
  374. return nil
  375. }
  376. htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
  377. lintZip(ctx, htmlList, htmlZip)
  378. textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
  379. lintZip(ctx, textList, textZip)
  380. xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
  381. lintZip(ctx, xmlList, xmlZip)
  382. return android.Paths{htmlZip, textZip, xmlZip}
  383. }
  384. type lintSingleton struct {
  385. htmlZip android.WritablePath
  386. textZip android.WritablePath
  387. xmlZip android.WritablePath
  388. }
  389. func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
  390. l.generateLintReportZips(ctx)
  391. l.copyLintDependencies(ctx)
  392. }
  393. func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
  394. if ctx.Config().AlwaysUsePrebuiltSdks() {
  395. return
  396. }
  397. var frameworkDocStubs android.Module
  398. ctx.VisitAllModules(func(m android.Module) {
  399. if ctx.ModuleName(m) == "framework-doc-stubs" {
  400. if frameworkDocStubs == nil {
  401. frameworkDocStubs = m
  402. } else {
  403. ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
  404. ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
  405. }
  406. }
  407. })
  408. if frameworkDocStubs == nil {
  409. if !ctx.Config().AllowMissingDependencies() {
  410. ctx.Errorf("lint: missing framework-doc-stubs")
  411. }
  412. return
  413. }
  414. ctx.Build(pctx, android.BuildParams{
  415. Rule: android.CpIfChanged,
  416. Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
  417. Output: copiedAnnotationsZipPath(ctx),
  418. })
  419. ctx.Build(pctx, android.BuildParams{
  420. Rule: android.CpIfChanged,
  421. Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
  422. Output: copiedAPIVersionsXmlPath(ctx),
  423. })
  424. }
  425. func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
  426. return android.PathForOutput(ctx, "lint", "annotations.zip")
  427. }
  428. func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
  429. return android.PathForOutput(ctx, "lint", "api_versions.xml")
  430. }
  431. func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
  432. if ctx.Config().UnbundledBuild() {
  433. return
  434. }
  435. var outputs []*lintOutputs
  436. var dirs []string
  437. ctx.VisitAllModules(func(m android.Module) {
  438. if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
  439. return
  440. }
  441. if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
  442. apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
  443. if apexInfo.IsForPlatform() {
  444. // There are stray platform variants of modules in apexes that are not available for
  445. // the platform, and they sometimes can't be built. Don't depend on them.
  446. return
  447. }
  448. }
  449. if l, ok := m.(lintOutputsIntf); ok {
  450. outputs = append(outputs, l.lintOutputs())
  451. }
  452. })
  453. dirs = android.SortedUniqueStrings(dirs)
  454. zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
  455. var paths android.Paths
  456. for _, output := range outputs {
  457. if p := get(output); p != nil {
  458. paths = append(paths, p)
  459. }
  460. }
  461. lintZip(ctx, paths, outputPath)
  462. }
  463. l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
  464. zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
  465. l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
  466. zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
  467. l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
  468. zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
  469. ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
  470. }
  471. func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
  472. if !ctx.Config().UnbundledBuild() {
  473. ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
  474. }
  475. }
  476. var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
  477. func init() {
  478. android.RegisterSingletonType("lint",
  479. func() android.Singleton { return &lintSingleton{} })
  480. registerLintBuildComponents(android.InitRegistrationContext)
  481. }
  482. func registerLintBuildComponents(ctx android.RegistrationContext) {
  483. ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
  484. ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
  485. })
  486. }
  487. func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
  488. paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
  489. sort.Slice(paths, func(i, j int) bool {
  490. return paths[i].String() < paths[j].String()
  491. })
  492. rule := android.NewRuleBuilder(pctx, ctx)
  493. rule.Command().BuiltTool("soong_zip").
  494. FlagWithOutput("-o ", outputPath).
  495. FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
  496. FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths)
  497. rule.Build(outputPath.Base(), outputPath.Base())
  498. }
  499. // Enforce the strict updatability linting to all applicable transitive dependencies.
  500. func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
  501. m := ctx.Module()
  502. if d, ok := m.(lintDepSetsIntf); ok && d.getStrictUpdatabilityLinting() {
  503. ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
  504. if a, ok := d.(lintDepSetsIntf); ok {
  505. a.setStrictUpdatabilityLinting(true)
  506. }
  507. })
  508. }
  509. }