in android/src/com/android/tools/idea/actions/annotations/InferAnnotations.kt [527:606]
override fun visitCallExpression(node: UCallExpression): Boolean {
super.visitCallExpression(node)
val calledMethod = node.resolve()
if (calledMethod != null) {
val calledConstraints = getConstraints(calledMethod)
val calledPermissionRequirements = calledConstraints.permissionReferences
if (calledPermissionRequirements != null && isUnconditionallyReachable(method, node) &&
!handlesException(node, getSecurityException(), true, SECURITY_EXCEPTION)
) {
if (constraints.addPermissionRequirement(calledPermissionRequirements, calledConstraints.requireAllPermissions)) {
numAnnotationsAdded++
if (!calledConstraints.readOnly || settings.includeBinaries) {
val signature = calledMethod.getSignature()
val explanation = calledConstraints.getPermissionAnnotationsString() + " because it calls " + signature
constraints.addExplanation(method, explanation)
}
}
}
}
val reflectiveReference = findReflectiveReference(node)
if (reflectiveReference != null) {
val reflectedConstraint = getConstraints(reflectiveReference)
if (reflectedConstraint.addAnnotation(KEEP_ANNOTATION)) {
numAnnotationsAdded++
if (!reflectedConstraint.readOnly || settings.includeBinaries) {
val signature = method.getSignature()
val explanation = "@Keep because it is called reflectively from $signature"
reflectedConstraint.addExplanation(reflectiveReference, explanation)
}
}
}
val name = node.methodName ?: node.methodIdentifier?.name
if (name != null && name.startsWith("enforce") &&
(
"enforceCallingOrSelfPermission" == name || "enforceCallingOrSelfUriPermission" == name ||
"enforceCallingPermission" == name || "enforceCallingUriPermission" == name ||
"enforcePermission" == name || "enforceUriPermission" == name
)
) {
// TODO: Determine whether this method is reached *unconditionally*
// and use that to merge multiple requirements in the method as well as
// the permission conditional flag
val args = node.valueArguments
if (args.isNotEmpty()) {
val first = args[0]
if (first is UReferenceExpression) {
val resolved = first.resolve()
if (resolved is PsiField) {
if (resolved.hasModifierProperty(PsiModifier.FINAL) && resolved.hasModifierProperty(PsiModifier.STATIC)) {
if (isUnconditionallyReachable(method, node) && !handlesException(node, getSecurityException(), true, SECURITY_EXCEPTION) &&
constraints.addPermissionRequirement(listOf(resolved), true)
) {
numAnnotationsAdded++
if (!constraints.readOnly || settings.includeBinaries) {
val explanation = constraints.getPermissionAnnotationsString() + " because it calls " + name
constraints.addExplanation(method, explanation)
}
}
return false
}
}
}
val v = first.evaluate()
if (v is String) {
if (isUnconditionallyReachable(method, node) && !handlesException(node, getSecurityException(), true, SECURITY_EXCEPTION) &&
constraints.addPermissionRequirement(listOf(v), true)
) {
numAnnotationsAdded++
if (!constraints.readOnly || settings.includeBinaries) {
val message = constraints.getPermissionAnnotationsString() + " because it calls " + name
constraints.addExplanation(method, message)
}
}
}
}
}
return false
}