• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.tools.metalava
2 
3 import com.android.tools.metalava.model.PackageItem
4 import java.io.File
5 import java.util.function.Predicate
6 
7 /**
8  *
9  * We permit a number of different styles:
10  * - exact match (foo)
11  * - prefix match (foo*, probably not intentional)
12  * - subpackage match (foo.*)
13  * - package and subpackage match (foo:foo.*)
14  * - explicit addition (+foo.*)
15  * - subtraction (+*:-foo.*)
16  *
17  * Real examples:
18  * args: "-stubpackages com.android.test.power ",
19  * args: "-stubpackages android.car* ",
20  * args: "-stubpackages com.android.ahat:com.android.ahat.*",
21  * args: "-force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*
22  *
23  * Note that doclava does *not* include subpackages by default: -stubpackage foo
24  * will match only foo, not foo.bar. Note also that "foo.*" will not match "foo",
25  * so doclava required you to supply both: "foo:foo.*".
26  *
27  * In metalava we've changed that: it's not likely that you want to
28  * match any subpackage of foo but not foo itself, so foo.* is taken
29  * to mean "foo" and "foo.*".
30  */
31 class PackageFilter {
32     val components: MutableList<PackageFilterComponent> = mutableListOf()
33 
matchesnull34     fun matches(qualifiedName: String): Boolean {
35         for (component in components.reversed()) {
36             if (component.filter.test(qualifiedName)) {
37                 return component.treatAsPositiveMatch
38             }
39         }
40         return false
41     }
42 
addPackagesnull43     fun addPackages(path: String) {
44         for (arg in path.split(File.pathSeparatorChar)) {
45             val treatAsPositiveMatch = !arg.startsWith("-")
46             val pkg = arg.removePrefix("-").removePrefix("+")
47             val index = pkg.indexOf('*')
48             if (index != -1) {
49                 if (index < pkg.length - 1) {
50                     throw DriverException(stderr = "Wildcards in stub packages must be at the end of the package: $pkg)")
51                 }
52                 val prefix = pkg.removeSuffix("*")
53                 if (prefix.endsWith(".")) {
54                     // In doclava, "foo.*" does not match "foo", but we want to do that.
55                     val exact = prefix.substring(0, prefix.length - 1)
56                     add(StringEqualsPredicate(exact), treatAsPositiveMatch)
57                 }
58                 add(StringPrefixPredicate(prefix), treatAsPositiveMatch)
59             } else {
60                 add(StringEqualsPredicate(pkg), treatAsPositiveMatch)
61             }
62         }
63     }
64 
addnull65     fun add(predicate: Predicate<String>, treatAsPositiveMatch: Boolean) {
66         components.add(PackageFilterComponent(predicate, treatAsPositiveMatch))
67     }
68 
matchesnull69     fun matches(packageItem: PackageItem): Boolean {
70         return matches(packageItem.qualifiedName())
71     }
72 
73     companion object {
parsenull74         fun parse(path: String): PackageFilter {
75             val filter = PackageFilter()
76             filter.addPackages(path)
77             return filter
78         }
79     }
80 }
81 
82 class StringPrefixPredicate(private val acceptedPrefix: String) : Predicate<String> {
testnull83     override fun test(candidatePackage: String): Boolean {
84         return candidatePackage.startsWith(acceptedPrefix)
85     }
86 }
87 
88 class StringEqualsPredicate(val acceptedPackage: String) : Predicate<String> {
testnull89     override fun test(candidatePackage: String): Boolean {
90         return candidatePackage == acceptedPackage
91     }
92 }
93 
94 /**
95  * One element of a PackageFilter.
96  * Detects packages and either either includes or excludes them from the filter
97  */
98 class PackageFilterComponent(val filter: Predicate<String>, val treatAsPositiveMatch: Boolean)
99