override fun visitCallExpression()

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
        }