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