Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion annotation-processors/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

import com.itsaky.androidide.build.config.BuildConfig
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
Expand Down Expand Up @@ -45,5 +46,5 @@ dependencies {
}

tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "17"
compilerOptions.jvmTarget.set(JvmTarget.JVM_17)
}
24 changes: 22 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,29 @@ android {

packaging {
resources {
excludes.add("META-INF/DEPENDENCIES")
excludes.add("META-INF/gradle/incremental.annotation.processors")
excludes += "META-INF/DEPENDENCIES"
excludes += "META-INF/gradle/incremental.annotation.processors"

pickFirsts += "kotlin/internal/internal.kotlin_builtins"
pickFirsts += "kotlin/reflect/reflect.kotlin_builtins"
pickFirsts += "kotlin/kotlin.kotlin_builtins"
pickFirsts += "kotlin/coroutines/coroutines.kotlin_builtins"
pickFirsts += "kotlin/ranges/ranges.kotlin_builtins"
pickFirsts += "kotlin/concurrent/atomics/atomics.kotlin_builtins"
pickFirsts += "kotlin/collections/collections.kotlin_builtins"
pickFirsts += "kotlin/annotation/annotation.kotlin_builtins"

pickFirsts += "META-INF/FastDoubleParser-LICENSE"
pickFirsts += "META-INF/thirdparty-LICENSE"
pickFirsts += "META-INF/FastDoubleParser-NOTICE"
pickFirsts += "META-INF/thirdparty-NOTICE"
}

jniLibs {
useLegacyPackaging = false
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
Expand Down Expand Up @@ -197,6 +212,10 @@ configurations.matching { it.name.contains("AndroidTest") }.configureEach {
exclude(group = "com.google.protobuf", module = "protobuf-lite")
}

configurations.configureEach {
exclude(group = "org.jetbrains.kotlin", module = "kotlin-android-extensions-runtime")
}

dependencies {
debugImplementation(libs.common.leakcanary)

Expand Down Expand Up @@ -278,6 +297,7 @@ dependencies {
implementation(projects.gradlePluginConfig)
implementation(projects.subprojects.aaptcompiler)
implementation(projects.subprojects.javacServices)
implementation(projects.subprojects.kotlinAnalysisApi)
implementation(projects.subprojects.shizukuApi)
implementation(projects.subprojects.shizukuManager)
implementation(projects.subprojects.shizukuProvider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,55 +28,60 @@ import com.itsaky.androidide.utils.ServiceLoader
*/
interface IJdkDistributionProvider {

/**
* The list of JDK distributions installed on the device.
*/
val installedDistributions: List<JdkDistribution>
/**
* The list of JDK distributions installed on the device.
*/
val installedDistributions: List<JdkDistribution>

/**
* Reloads the installed JDK distributions. This function is synchronous and should not be called
* on the UI thread.
*/
@WorkerThread
fun loadDistributions()
/**
* Reloads the installed JDK distributions. This function is synchronous and should not be called
* on the UI thread.
*/
@WorkerThread
fun loadDistributions()

/**
* Get the [JdkDistribution] instance for the given java version.
*
* @return The [JdkDistribution] instance for the given java version, or `null` if no such
* distribution is found.
*/
fun forVersion(javaVersion: String) : JdkDistribution? =
installedDistributions.firstOrNull { it.javaVersion == javaVersion }
/**
* Get the [JdkDistribution] instance for the given java version.
*
* @return The [JdkDistribution] instance for the given java version, or `null` if no such
* distribution is found.
*/
fun forVersion(javaVersion: String): JdkDistribution? =
installedDistributions.firstOrNull { it.javaVersion == javaVersion }


/**
* Get the [JdkDistribution] instance for the given java home.
*
* @return The [JdkDistribution] instance for the given java home, or `null` if no such
* distribution is found.
*/
fun forJavaHome(javaHome: String) : JdkDistribution? =
installedDistributions.firstOrNull { it.javaHome == javaHome }
/**
* Get the [JdkDistribution] instance for the given java home.
*
* @return The [JdkDistribution] instance for the given java home, or `null` if no such
* distribution is found.
*/
fun forJavaHome(javaHome: String): JdkDistribution? =
installedDistributions.firstOrNull { it.javaHome == javaHome }

companion object {
companion object {

/**
* The default java version.
*/
const val DEFAULT_JAVA_VERSION = "17"
/**
* The default Java version.
*/
const val DEFAULT_JAVA_RELEASE = 21

private val _instance by lazy {
ServiceLoader.load(
IJdkDistributionProvider::class.java,
IJdkDistributionProvider::class.java.classLoader
).findFirstOrThrow()
}
/**
* The default java version.
*/
const val DEFAULT_JAVA_VERSION = DEFAULT_JAVA_RELEASE.toString()

/**
* Get instance of [IJdkDistributionProvider].
*/
@JvmStatic
fun getInstance(): IJdkDistributionProvider = _instance
}
private val _instance by lazy {
ServiceLoader.load(
IJdkDistributionProvider::class.java,
IJdkDistributionProvider::class.java.classLoader
).findFirstOrThrow()
}

/**
* Get instance of [IJdkDistributionProvider].
*/
@JvmStatic
fun getInstance(): IJdkDistributionProvider = _instance
}
}
13 changes: 9 additions & 4 deletions composite-builds/build-deps/java-compiler/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
*/

plugins {
id("java-library")
id("java-library")
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

dependencies {
annotationProcessor(libs.google.auto.service)
implementation(libs.google.auto.service.annotations)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

package javac.internal.jrtfs;

import com.google.auto.service.AutoService;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
Expand Down Expand Up @@ -53,6 +55,7 @@
* but also compiled and delivered as part of the jrtfs.jar to support access
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
*/
@AutoService(FileSystemProvider.class)
public final class JrtFileSystemProvider extends FileSystemProvider {

private volatile FileSystem theFileSystem;
Expand Down
39 changes: 25 additions & 14 deletions composite-builds/build-logic/desugaring/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

/*
* This file is part of AndroidIDE.
*
Expand All @@ -16,26 +19,34 @@
*/

plugins {
`kotlin-dsl`
`kotlin-dsl`
}

dependencies {
implementation(gradleApi())
implementation(libs.composite.desugaringCore)
implementation(gradleApi())
implementation(libs.composite.desugaringCore)

compileOnly(libs.android.gradle.plugin)
compileOnly(libs.android.gradle.plugin)

testImplementation(libs.tests.junit)
testImplementation(libs.tests.google.truth)
testImplementation(libs.tests.junit)
testImplementation(libs.tests.google.truth)
}

gradlePlugin {
plugins {
create("desugaring") {
id = "com.itsaky.androidide.desugaring"
implementationClass = "com.itsaky.androidide.desugaring.DesugarGradlePlugin"
displayName = "AndroidIDE Method Desugaring Plugin"
description = "Gradle plugin for method desugaring in Android projects."
}
}
plugins {
create("desugaring") {
id = "com.itsaky.androidide.desugaring"
implementationClass = "com.itsaky.androidide.desugaring.DesugarGradlePlugin"
displayName = "AndroidIDE Method Desugaring Plugin"
description = "Gradle plugin for method desugaring in Android projects."
}
}
}

tasks.withType<KotlinCompile> {
compilerOptions {
apiVersion.set(KotlinVersion.KOTLIN_2_1)
languageVersion.set(KotlinVersion.KOTLIN_2_1)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package com.itsaky.androidide.desugaring

import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Type

/**
* Replaces all bytecode references to one or more classes within a method body.
*
* Covered visit sites:
* - [visitMethodInsn] — owner and embedded descriptor
* - [visitFieldInsn] — owner and field descriptor
* - [visitTypeInsn] — NEW / CHECKCAST / INSTANCEOF / ANEWARRAY operand
* - [visitLdcInsn] — class-literal Type constants
* - [visitLocalVariable] — local variable descriptor and generic signature
* - [visitMultiANewArrayInsn]— array descriptor
* - [visitTryCatchBlock] — caught exception type
*
* @param classReplacements Mapping from source internal name (slash-notation)
* to target internal name (slash-notation). An empty map is a no-op.
*
* @author Akash Yadav
*/
class ClassRefReplacingMethodVisitor(
api: Int,
mv: MethodVisitor?,
private val classReplacements: Map<String, String>,
) : MethodVisitor(api, mv) {

override fun visitMethodInsn(
opcode: Int,
owner: String,
name: String,
descriptor: String,
isInterface: Boolean,
) {
super.visitMethodInsn(
opcode,
replace(owner),
name,
replaceInDescriptor(descriptor),
isInterface,
)
}

override fun visitFieldInsn(
opcode: Int,
owner: String,
name: String,
descriptor: String,
) {
super.visitFieldInsn(
opcode,
replace(owner),
name,
replaceInDescriptor(descriptor),
)
}

override fun visitTypeInsn(opcode: Int, type: String) {
super.visitTypeInsn(opcode, replace(type))
}

override fun visitLdcInsn(value: Any?) {
// Replace class-literal constants: Foo.class → Bar.class
if (value is Type && value.sort == Type.OBJECT) {
val replaced = replace(value.internalName)
if (replaced !== value.internalName) {
super.visitLdcInsn(Type.getObjectType(replaced))
return
}
}
super.visitLdcInsn(value)
}

override fun visitLocalVariable(
name: String,
descriptor: String,
signature: String?,
start: Label,
end: Label,
index: Int,
) {
super.visitLocalVariable(
name,
replaceInDescriptor(descriptor),
replaceInSignature(signature),
start,
end,
index,
)
}

override fun visitMultiANewArrayInsn(descriptor: String, numDimensions: Int) {
super.visitMultiANewArrayInsn(replaceInDescriptor(descriptor), numDimensions)
}

override fun visitTryCatchBlock(
start: Label,
end: Label,
handler: Label,
type: String?,
) {
super.visitTryCatchBlock(start, end, handler, type?.let { replace(it) })
}

// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------

/** Replaces a bare internal class name (slash-notation). */
private fun replace(internalName: String): String =
classReplacements[internalName] ?: internalName

/**
* Substitutes every `L<from>;` token in a JVM descriptor or generic
* signature with `L<to>;`.
*/
private fun replaceInDescriptor(descriptor: String): String {
if (classReplacements.isEmpty()) return descriptor
var result = descriptor
for ((from, to) in classReplacements) {
result = result.replace("L$from;", "L$to;")
}
return result
}

/** Delegates to [replaceInDescriptor]; returns `null` for `null` input. */
private fun replaceInSignature(signature: String?): String? =
signature?.let { replaceInDescriptor(it) }
}
Loading
Loading