• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.metalava.model
18 
19 import java.io.File
20 import java.util.function.Predicate
21 
22 /**
23  * Checks to see if a package name matches a set of configured rules.
24  *
25  * This supports a number of rule styles:
26  * - exact match (foo)
27  * - prefix match (foo*, probably not intentional)
28  * - package and subpackage match (foo.*)
29  * - explicit addition (+foo.*)
30  * - subtraction (+*:-foo.*)
31  *
32  * Real examples: args: "-stubpackages com.android.test.power ", args: "-stubpackages android.car*
33  * ", args: "-stubpackages com.android.ahat:com.android.ahat.*", args:
34  * "-force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*
35  */
36 class PackageFilter {
37     private val components: MutableList<PackageFilterComponent> = mutableListOf()
38 
matchesnull39     fun matches(qualifiedName: String): Boolean {
40         for (component in components.reversed()) {
41             if (component.filter.test(qualifiedName)) {
42                 return component.treatAsPositiveMatch
43             }
44         }
45         return false
46     }
47 
addPackagesnull48     internal fun addPackages(path: String) {
49         for (arg in path.split(File.pathSeparatorChar)) {
50             val treatAsPositiveMatch = !arg.startsWith("-")
51             val pkg = arg.removePrefix("-").removePrefix("+")
52             val index = pkg.indexOf('*')
53             if (index != -1) {
54                 if (index < pkg.length - 1) {
55                     throw IllegalStateException(
56                         "Wildcards in stub packages must be at the end of the package: $pkg"
57                     )
58                 }
59                 val prefix = pkg.removeSuffix("*")
60                 if (prefix.endsWith(".")) {
61                     // In doclava, "foo.*" does not match "foo", but we want to do that.
62                     val exact = prefix.substring(0, prefix.length - 1)
63                     add(StringEqualsPredicate(exact), treatAsPositiveMatch)
64                 }
65                 add(StringPrefixPredicate(prefix), treatAsPositiveMatch)
66             } else {
67                 add(StringEqualsPredicate(pkg), treatAsPositiveMatch)
68             }
69         }
70     }
71 
addnull72     private fun add(predicate: Predicate<String>, treatAsPositiveMatch: Boolean) {
73         components.add(PackageFilterComponent(predicate, treatAsPositiveMatch))
74     }
75 
matchesnull76     fun matches(packageItem: PackageItem): Boolean {
77         return matches(packageItem.qualifiedName())
78     }
79 
80     companion object {
parsenull81         fun parse(path: String): PackageFilter {
82             val filter = PackageFilter()
83             filter.addPackages(path)
84             return filter
85         }
86     }
87 }
88 
89 internal class StringPrefixPredicate(private val acceptedPrefix: String) : Predicate<String> {
testnull90     override fun test(candidatePackage: String): Boolean {
91         return candidatePackage.startsWith(acceptedPrefix)
92     }
93 }
94 
95 internal class StringEqualsPredicate(private val acceptedPackage: String) : Predicate<String> {
testnull96     override fun test(candidatePackage: String): Boolean {
97         return candidatePackage == acceptedPackage
98     }
99 }
100 
101 /**
102  * One element of a PackageFilter. Detects packages and either includes or excludes them from the
103  * filter
104  */
105 internal class PackageFilterComponent(
106     val filter: Predicate<String>,
107     val treatAsPositiveMatch: Boolean,
108 )
109