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