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

com.autonomousapps.model.internal.ProjectVariant.kt Maven / Gradle / Ivy

There is a newer version: 2.6.1
Show newest version
// Copyright (c) 2024. Tony Robalik.
// SPDX-License-Identifier: Apache-2.0
package com.autonomousapps.model.internal

import com.autonomousapps.internal.unsafeLazy
import com.autonomousapps.internal.utils.flatMapToOrderedSet
import com.autonomousapps.internal.utils.flatMapToSet
import com.autonomousapps.internal.utils.fromJson
import com.autonomousapps.model.internal.CodeSource.Kind
import com.autonomousapps.model.Coordinates
import com.autonomousapps.model.ProjectCoordinates
import com.autonomousapps.model.declaration.Variant
import com.autonomousapps.model.internal.intermediates.consumer.MemberAccess
import com.squareup.moshi.JsonClass
import org.gradle.api.file.Directory

/** Represents a variant-specific view of the project under analysis. */
@Suppress("MemberVisibilityCanBePrivate") // deliberate API
@JsonClass(generateAdapter = false)
internal data class ProjectVariant(
  val coordinates: ProjectCoordinates,
  val buildType: String?,
  val flavor: String?,
  val variant: Variant,
  val sources: Set,
  val classpath: Set,
  val annotationProcessors: Set,
  val testInstrumentationRunner: String?
) {

  val codeSource: List by unsafeLazy {
    sources.filterIsInstance()
  }

  val usedNonAnnotationClassesBySrc: Set by unsafeLazy {
    codeSource.flatMapToSet {
      it.usedNonAnnotationClasses
    }
  }

  val usedAnnotationClassesBySrc: Set by unsafeLazy {
    codeSource.flatMapToSet {
      it.usedAnnotationClasses
    }
  }

  /** Invisible annotations are required at compile time but not at runtime. */
  val usedInvisibleAnnotationClassesBySrc: Set by unsafeLazy {
    codeSource.flatMapToSet {
      it.usedInvisibleAnnotationClasses
    }
  }

  /**
   * For typealiases, we check for presence in the bytecode in any context, annotation or otherwise. We do not check
   * usages in Android res.
   */
  val usedClassesBySrc: Set by unsafeLazy {
    usedNonAnnotationClassesBySrc + usedAnnotationClassesBySrc
  }

  val usedClassesByRes: Set by unsafeLazy {
    androidResSource.flatMapToSet {
      it.usedClasses
    }
  }

  /** All class references from any context. */
  val usedClasses: Set by unsafeLazy {
    codeSource.flatMapToSet {
      usedClassesBySrc + usedClassesByRes
    }
  }

  val usedNonAnnotationClasses: Set by unsafeLazy {
    usedClassesByRes + usedNonAnnotationClassesBySrc
  }

  val exposedClasses: Set by unsafeLazy {
    codeSource.flatMapToSet {
      it.exposedClasses
    }
  }

  val implementationClasses: Set by unsafeLazy {
    usedNonAnnotationClasses - exposedClasses
  }

  val androidResSource: List by unsafeLazy {
    sources.filterIsInstance()
  }

  val androidAssetsSource: List by unsafeLazy {
    sources.filterIsInstance()
  }

  val imports: Set by unsafeLazy {
    codeSource.flatMapToOrderedSet { it.imports }
  }

  // /**
  //  * Every member access from this project to classes in another module. cf [usedClasses], which is a flat set of
  //  * referenced class names.
  //  */
  // val memberAccesses: Set by unsafeLazy {
  //   codeSource.flatMapToOrderedSet { src ->
  //     src.binaryClassAccesses.entries.flatMap { entry -> entry.value }
  //   }
  // }

  val javaImports: Set by unsafeLazy {
    codeSource.filter { it.kind == Kind.JAVA }
      .flatMapToOrderedSet { it.imports }
  }

  val kotlinImports: Set by unsafeLazy {
    codeSource.filter { it.kind == Kind.KOTLIN }
      .flatMapToOrderedSet { it.imports }
  }

  val groovyImports: Set by unsafeLazy {
    codeSource.filter { it.kind == Kind.GROOVY }
      .flatMapToOrderedSet { it.imports }
  }

  val scalaImports: Set by unsafeLazy {
    codeSource.filter { it.kind == Kind.SCALA }
      .flatMapToOrderedSet { it.imports }
  }

  internal fun dependencies(dependenciesDir: Directory): Set {
    return classpath.asSequence()
      .plus(annotationProcessors)
      .map {
        val file = dependenciesDir.file(it.toFileName())
        if (file.asFile.exists()) {
          file.fromJson()
        } else {
          error("No file ${it.toFileName()}")
        }
      }
      .toSet()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy