Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1b069cb
fix: add ability to re-write class name references in desugar plugin
itsaky-adfa Mar 19, 2026
a70fd66
feat: integrate Kotlin analysis API
itsaky-adfa Mar 19, 2026
4ca1e97
Merge branch 'stage' into fix/ADFA-3366-include-analysis-api-as-depen…
itsaky-adfa Mar 19, 2026
43286a6
fix: update kotlin-android to latest version
itsaky-adfa Mar 23, 2026
f1fe62f
fix: remove UnsafeImpl
itsaky-adfa Mar 25, 2026
6e6d8b3
fix: update kotlin-android to latest version
itsaky-adfa Mar 25, 2026
b208658
fix: replace usages of Unsafe with UnsafeImpl
itsaky-adfa Mar 24, 2026
c844ad2
fix: make Kotlin LSP no-op
itsaky-adfa Mar 23, 2026
58db2cb
feat: configure K2 standalone session when setting up LSP
itsaky-adfa Mar 24, 2026
bf7acd1
fix: JvmTarget resolution fails for input "21"
itsaky-adfa Mar 24, 2026
dc62a51
fix: do not early-init VirtualFileSystem
itsaky-adfa Mar 24, 2026
4b1c8e4
fix: remove replaceClass desugar instruction for Unsafe
itsaky-adfa Mar 25, 2026
b14f6ee
fix: ensure boot class path is added as dependency to Android modules
itsaky-adfa Mar 26, 2026
7c14cd3
Merge branch 'stage' into fix/ADFA-3318-setup-K2-LSP-infra
itsaky-adfa Apr 15, 2026
f5014bd
fix: remove unused class
itsaky-adfa Apr 15, 2026
7348556
fix: compilation error
itsaky-adfa Apr 17, 2026
3f2452c
Merge branch 'stage' into fix/ADFA-3318-setup-K2-LSP-infra
itsaky-adfa Apr 17, 2026
ef33e2e
Merge branch 'stage' into fix/ADFA-3318-setup-K2-LSP-infra
itsaky-adfa Apr 17, 2026
69a50a4
Merge branch 'stage' into fix/ADFA-3318-setup-K2-LSP-infra
itsaky-adfa Apr 17, 2026
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
Binary file modified assets/core.cgt
Binary file not shown.
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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/

package com.itsaky.androidide.desugaring.dsl

import com.itsaky.androidide.desugaring.internal.parsing.InsnLexer
Expand All @@ -29,32 +30,21 @@ import javax.inject.Inject
/**
* Defines replacements for desugaring.
*
* Two replacement strategies are supported and can be combined freely:
*
* - **Method-level** ([replaceMethod]): replaces a specific method call with
* another, with full control over opcodes and descriptors.
* - **Class-level** ([replaceClass]): rewrites every bytecode reference to a
* given class (owners, descriptors, type instructions, LDC constants, etc.)
* with a replacement class. This is a broader, structural operation.
*
* When both apply to the same instruction, method-level replacement wins
* because it runs first in the visitor chain.
*
* @author Akash Yadav
*/
abstract class DesugarReplacementsContainer @Inject constructor(
private val objects: ObjectFactory,
private val objects: ObjectFactory
) {

internal val includePackages = TreeSet<String>()

internal val instructions =
mutableMapOf<ReplaceMethodInsnKey, ReplaceMethodInsn>()

/** Class-level replacements: dot-notation source → dot-notation target. */
internal val classReplacements = mutableMapOf<String, String>()

companion object {

private val PACKAGE_NAME_REGEX =
Regex("""^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*${'$'}""")
}
Expand Down Expand Up @@ -94,22 +84,6 @@ abstract class DesugarReplacementsContainer @Inject constructor(
addReplaceInsns(instruction)
}

/**
* Replaces every bytecode reference to [fromClass] with [toClass].
*
* This rewrites:
* - Instruction owners (`INVOKEVIRTUAL`, `GETFIELD`, `NEW`, `CHECKCAST`, …)
* - Type descriptors and generic signatures in method bodies
* - Class-literal LDC constants (`Foo.class`)
* - Field and method *declaration* descriptors in the instrumented class
*
* Class names can be provided in dot-notation (`com.example.Foo`) or
* slash-notation (`com/example/Foo`).
*
* Note: unlike [replaceMethod], class-level replacement is applied to
* **all** instrumented classes regardless of [includePackage] filters,
* because any class may contain a reference to the replaced one.
*/
fun replaceClass(fromClass: String, toClass: String) {
require(fromClass.isNotBlank()) { "fromClass must not be blank." }
require(toClass.isNotBlank()) { "toClass must not be blank." }
Expand All @@ -118,11 +92,6 @@ abstract class DesugarReplacementsContainer @Inject constructor(
classReplacements[from] = to
}

/**
* Replaces every bytecode reference to [fromClass] with [toClass].
*
* @throws UnsupportedOperationException for array or primitive types.
*/
fun replaceClass(fromClass: Class<*>, toClass: Class<*>) {
require(!fromClass.isArray && !fromClass.isPrimitive) {
"Array and primitive types are not supported for class replacement."
Expand Down
24 changes: 12 additions & 12 deletions git-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ android {
}

dependencies {
implementation(libs.androidx.core.ktx.v1120)
implementation(libs.androidx.appcompat.v171)
implementation(libs.google.material)
implementation(libs.git.jgit)
coreLibraryDesugaring(libs.desugar.jdk.libs.v215)
implementation(libs.common.kotlin.coroutines.core)
implementation(libs.common.kotlin.coroutines.android)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.security.crypto)
implementation(libs.androidx.core.ktx.v1120)
implementation(libs.androidx.appcompat.v171)
implementation(libs.google.material)
implementation(libs.git.jgit)
coreLibraryDesugaring(libs.desugar.jdk.libs.v215)
implementation(libs.common.kotlin.coroutines.core)
implementation(libs.common.kotlin.coroutines.android)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.security.crypto)

testImplementation(libs.tests.junit)
androidTestImplementation(libs.tests.androidx.junit)
androidTestImplementation(libs.tests.androidx.espresso.core)
testImplementation(libs.tests.junit)
androidTestImplementation(libs.tests.androidx.junit)
androidTestImplementation(libs.tests.androidx.espresso.core)
}
Loading
Loading