1 package com.android.tools.metalava.doclava1
2 
3 import com.android.tools.metalava.Options
4 import com.android.tools.metalava.model.ClassItem
5 import com.android.tools.metalava.model.Codebase
6 import com.android.tools.metalava.model.Item
7 import com.android.tools.metalava.model.MemberItem
8 import com.android.tools.metalava.model.PackageItem
9 import com.android.tools.metalava.options
10 import java.util.function.Predicate
11 
12 // Ported from doclava1
13 
14 /**
15  * Predicate that decides if the given member should be considered part of an
16  * API surface area. To make the most accurate decision, it searches for
17  * signals on the member, all containing classes, and all containing packages.
18  */
19 class ApiPredicate(
20     val codebase: Codebase,
21     /**
22      * Set if the value of [MemberItem.hasShowAnnotation] should be
23      * ignored. That is, this predicate will assume that all encountered members
24      * match the "shown" requirement.
25      *
26      * This is typically useful when generating "current.txt", when no
27      * [Options.showAnnotations] have been defined.
28      */
29     private val ignoreShown: Boolean = options.showUnannotated,
30 
31     /**
32      * Set if the value of [MemberItem.removed] should be ignored.
33      * That is, this predicate will assume that all encountered members match
34      * the "removed" requirement.
35      *
36      * This is typically useful when generating "removed.txt", when it's okay to
37      * reference both current and removed APIs.
38      */
39     private val ignoreRemoved: Boolean = false,
40 
41     /**
42      * Set what the value of [MemberItem.removed] must be equal to in
43      * order for a member to match.
44      *
45      * This is typically useful when generating "removed.txt", when you only
46      * want to match members that have actually been removed.
47      */
48     private val matchRemoved: Boolean = false,
49 
50     /** Whether we allow matching items loaded from jar files instead of sources */
51     private val allowFromJar: Boolean = true,
52 
53     /** Whether we should include doc-only items */
54     private val includeDocOnly: Boolean = false
55 ) : Predicate<Item> {
56 
testnull57     override fun test(member: Item): Boolean {
58         if (!allowFromJar && member.isFromClassPath()) {
59             return false
60         }
61 
62         var visible = member.isPublic || member.isProtected // TODO: Should this use checkLevel instead?
63         var hidden = member.hidden
64         if (!visible || hidden) {
65             return false
66         }
67 
68         var hasShowAnnotation = ignoreShown || member.hasShowAnnotation()
69         var docOnly = member.docOnly
70         var removed = member.removed
71 
72         var clazz: ClassItem? = when (member) {
73             is MemberItem -> member.containingClass()
74             is ClassItem -> member
75             else -> null
76         }
77 
78         if (clazz != null) {
79             var pkg: PackageItem? = clazz.containingPackage()
80             while (pkg != null) {
81                 hidden = hidden or pkg.hidden
82                 docOnly = docOnly or pkg.docOnly
83                 removed = removed or pkg.removed
84                 pkg = pkg.containingPackage()
85             }
86         }
87         while (clazz != null) {
88             visible = visible and (clazz.isPublic || clazz.isProtected)
89             hasShowAnnotation = hasShowAnnotation or (ignoreShown || clazz.hasShowAnnotation())
90             hidden = hidden or clazz.hidden
91             docOnly = docOnly or clazz.docOnly
92             removed = removed or clazz.removed
93             clazz = clazz.containingClass()
94         }
95 
96         if (ignoreRemoved) {
97             removed = matchRemoved
98         }
99 
100         if (docOnly && includeDocOnly) {
101             docOnly = false
102         }
103 
104         return visible && hasShowAnnotation && !hidden && !docOnly && removed == matchRemoved
105     }
106 }
107