All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.autonomousapps.internal.AnalyzedJar.kt Maven / Gradle / Ivy

There is a newer version: 2.0.2
Show newest version
package com.autonomousapps.internal

import com.autonomousapps.internal.utils.mapToOrderedSet
import com.autonomousapps.internal.utils.reallyAll
import java.lang.annotation.RetentionPolicy

/**
 * Algorithm:
 *
 * Jar must _only_ contain:
 * 1. Annotation classes with `CLASS` or `SOURCE` retention policies (or no policy => `CLASS` is default).
 * 2. The above, plus types that only exist to provide a sort of "namespace". For example,
 *    `org.jetbrains.annotations.ApiStatus` has no members. It only has inner classes which are themselves
 *     annotations that comply with 1.
 * 3. All of the above, plus types that are only used by the annotations in the jar that comply with 1. For example, the
 *    `@org.intellij.lang.annotations.PrintFormat` annotation uses a class (in this case defined in the same file),
 *    `org.intellij.lang.annotations.PrintFormatPattern`. The assumption here is that such classes
 *    (`PrintFormatPattern`) are only required during compilation, for their associated compile-only annotations.
 *    // TODO unit tests for this class
 */
internal class AnalyzedJar(
  analyzedClasses: Set,
  val ktFiles: List
) {

  val classNames: Set = analyzedClasses.mapToOrderedSet { it.className }

  val isCompileOnlyCandidate: Boolean =
    if (analyzedClasses.isEmpty()) {
      false
    } else {
      var value = true
      for (analyzedClass in analyzedClasses) {
        if (isNotCompileOnlyAnnotation(analyzedClass)) {
          // it is ok if it's not an annotation class, if it is a "namespace class".
          if (!isNamespaceClass(analyzedClass, analyzedClasses)) {
            // it's ok if it is not a namespace class, if it's private (non-public)
            if (isPublic(analyzedClass)) {
              // it's ok if it's public, if it's an enum
              if (!isEnum(analyzedClass)) {
                value = false
                break
              }
            }
          }
        }
      }
      value
    }

  val isSecurityProvider: Boolean = analyzedClasses.any { it.superClassName == "java/security/Provider" }

  /**
   * Map of class names to the public constants they declare.
   */
  val constants: Map> = analyzedClasses.map {
    it.className to it.constantFields
  }.toMap()

  private fun RetentionPolicy?.isCompileOnly() = this == RetentionPolicy.CLASS || this == RetentionPolicy.SOURCE

  private fun isCompileOnlyAnnotation(analyzedClass: AnalyzedClass): Boolean =
    analyzedClass.retentionPolicy.isCompileOnly()

  private fun isNotCompileOnlyAnnotation(analyzedClass: AnalyzedClass): Boolean =
    !isCompileOnlyAnnotation(analyzedClass)

  private fun isNamespaceClass(analyzedClass: AnalyzedClass, analyzedClasses: Set): Boolean =
    analyzedClass.hasNoMembers && analyzedClasses
      .filter { analyzedClass.innerClasses.contains(it.className) }
      .reallyAll { isCompileOnlyAnnotation(it) }

  private fun isPublic(analyzedClass: AnalyzedClass): Boolean =
    analyzedClass.access == Access.PUBLIC || analyzedClass.access == Access.PROTECTED

  private fun isEnum(analyzedClass: AnalyzedClass): Boolean = analyzedClass.superClassName == "java/lang/Enum"
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy