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 allowClassesFromClasspath: Boolean = options.allowClassesFromClasspath, 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 // Type Parameter references (e.g. T) aren't actual types, skip all visibility checks 57 if (member is ClassItem && member.isTypeParameter) { 58 return true 59 } 60 61 if (!allowClassesFromClasspath && member.isFromClassPath()) { 62 return false 63 } 64 65 var visible = member.isPublic || member.isProtected // TODO: Should this use checkLevel instead? 66 var hidden = member.hidden 67 if (!visible || hidden) { 68 return false 69 } 70 71 var hasShowAnnotation = ignoreShown || member.hasShowAnnotation() 72 var docOnly = member.docOnly 73 var removed = member.removed 74 75 var clazz: ClassItem? = when (member) { 76 is MemberItem -> member.containingClass() 77 is ClassItem -> member 78 else -> null 79 } 80 81 if (clazz != null) { 82 var pkg: PackageItem? = clazz.containingPackage() 83 while (pkg != null) { 84 hidden = hidden or pkg.hidden 85 docOnly = docOnly or pkg.docOnly 86 removed = removed or pkg.removed 87 pkg = pkg.containingPackage() 88 } 89 } 90 while (clazz != null) { 91 visible = visible and (clazz.isPublic || clazz.isProtected) 92 hasShowAnnotation = hasShowAnnotation or (ignoreShown || clazz.hasShowAnnotation()) 93 hidden = hidden or clazz.hidden 94 docOnly = docOnly or clazz.docOnly 95 removed = removed or clazz.removed 96 clazz = clazz.containingClass() 97 } 98 99 if (ignoreRemoved) { 100 removed = matchRemoved 101 } 102 103 if (docOnly && includeDocOnly) { 104 docOnly = false 105 } 106 107 return visible && hasShowAnnotation && !hidden && !docOnly && removed == matchRemoved 108 } 109 } 110