diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index b38ea905d..ea12ba260 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -116,6 +116,7 @@
+
diff --git a/core/app/build.gradle.kts b/core/app/build.gradle.kts
index f21cdc6ce..ff00e1018 100755
--- a/core/app/build.gradle.kts
+++ b/core/app/build.gradle.kts
@@ -129,7 +129,8 @@ dependencies {
// Local projects here
implementation(projects.core.actions)
implementation(projects.core.common)
- implementation(projects.core.indexing)
+ implementation(projects.core.indexingApi)
+ implementation(projects.core.indexingCore)
implementation(projects.core.lspApi)
implementation(projects.core.projects)
implementation(projects.core.resources)
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/ICloneable.kt b/core/common/src/main/java/com/itsaky/androidide/models/ICloneable.kt
similarity index 94%
rename from java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/ICloneable.kt
rename to core/common/src/main/java/com/itsaky/androidide/models/ICloneable.kt
index d3ad0e584..c7dd4108e 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/ICloneable.kt
+++ b/core/common/src/main/java/com/itsaky/androidide/models/ICloneable.kt
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.lsp.java.indexing
+package com.itsaky.androidide.models
/**
* Anything that can be cloned.
diff --git a/core/database/src/main/java/com/itsaky/androidide/db/IRealmProvider.kt b/core/database/src/main/java/com/itsaky/androidide/db/IRealmProvider.kt
index 539d91208..2bf6ec341 100644
--- a/core/database/src/main/java/com/itsaky/androidide/db/IRealmProvider.kt
+++ b/core/database/src/main/java/com/itsaky/androidide/db/IRealmProvider.kt
@@ -54,6 +54,28 @@ interface IRealmProvider {
*/
const val PATH_SEPARATOR = '/'
+ /**
+ * Create the path for the given segments.
+ *
+ * @param first The first (root) path segment.
+ * @param rest The rest of the path segments.
+ * @return The created path string.
+ */
+ @JvmStatic
+ fun createPath(first: String, vararg rest: String): String {
+
+ val sb = StringBuilder()
+ sb.append(PATH_SEPARATOR)
+ sb.append(first)
+
+ for (segment in rest) {
+ sb.append(PATH_SEPARATOR)
+ sb.append(segment)
+ }
+
+ return sb.toString()
+ }
+
/**
* Get the [IRealmProvider] instance, finding the implementation if necessary.
*/
diff --git a/core/indexing/.gitignore b/core/indexing-api/.gitignore
similarity index 100%
rename from core/indexing/.gitignore
rename to core/indexing-api/.gitignore
diff --git a/core/indexing/build.gradle.kts b/core/indexing-api/build.gradle.kts
similarity index 93%
rename from core/indexing/build.gradle.kts
rename to core/indexing-api/build.gradle.kts
index 705f6d522..1c0dd6055 100644
--- a/core/indexing/build.gradle.kts
+++ b/core/indexing-api/build.gradle.kts
@@ -29,7 +29,7 @@ groupConfig {
}
android {
- namespace = "${BuildConfig.packageName}.indexing"
+ namespace = "${BuildConfig.packageName}.indexing.api"
}
dependencies {
@@ -38,6 +38,7 @@ dependencies {
api(projects.core.common)
api(projects.core.database)
+ api(projects.core.projects)
api(projects.logging.logger)
api(projects.utilities.shared)
}
\ No newline at end of file
diff --git a/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/AbstractDBIndex.kt b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/AbstractDBIndex.kt
new file mode 100644
index 000000000..bb1718e80
--- /dev/null
+++ b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/AbstractDBIndex.kt
@@ -0,0 +1,59 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing
+
+import io.realm.Realm
+
+/**
+ * Abstract implementation of [IIndex] for indexing data in the database.
+ *
+ * @property params The index parameters.
+ * @author Akash Yadav
+ */
+abstract class AbstractDBIndex(
+ protected val params: IIndexParams?
+) : IIndex {
+
+ protected abstract val realm: Realm
+
+ override fun index(symbol: T) {
+ realm.executeTransaction {
+ it.insertOrUpdate(symbol)
+ }
+ }
+
+ override fun indexAsync(symbol: T) {
+ realm.executeTransactionAsync {
+ it.insertOrUpdate(symbol)
+ }
+ }
+
+ override fun indexAll(symbols: Collection) {
+ realm.executeTransaction {
+ it.insertOrUpdate(symbols)
+ }
+ }
+
+ override fun indexAllAsync(symbols: Collection) {
+ realm.executeTransactionAsync { it.insertOrUpdate(symbols) }
+ }
+
+ override fun delete() {
+ realm.deleteAll()
+ }
+}
\ No newline at end of file
diff --git a/core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndex.kt b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndex.kt
similarity index 65%
rename from core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndex.kt
rename to core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndex.kt
index a31568765..f7aa0822f 100644
--- a/core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndex.kt
+++ b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndex.kt
@@ -18,16 +18,26 @@
package com.itsaky.androidide.indexing
import com.itsaky.androidide.db.IRealmProvider
-import com.itsaky.androidide.indexing.internal.DefaultIndex
/**
* An index of symbols of type [IndexableT].
*
* @author Akash Yadav
*/
-interface IIndex {
+interface IIndex {
companion object {
+
+ /**
+ * The default batch size for indexing.
+ */
+ const val DEFAULT_PUT_BATCH_SIZE = 100
+
+ /**
+ * Base path for indices.
+ */
+ const val INDEX_BASE_PATH = "${IRealmProvider.PATH_SEPARATOR}index"
+
private const val DEF_IS_ASYNC = true
/**
@@ -53,40 +63,39 @@ interface IIndex {
*
* @param symbol The symbol to index.
*/
- fun index(symbol: IndexableT, async: Boolean = DEF_IS_ASYNC)
+ fun index(symbol: IndexableT)
+
+ /**
+ * Index the given symbol asynchronously.
+ *
+ * @param symbol The symbol to index.
+ */
+ fun indexAsync(symbol: IndexableT)
/**
* Index the given symbols.
*
* @param symbols The symbols to index.
*/
- fun indexAll(symbols: Collection, async: Boolean = DEF_IS_ASYNC) = indexBatched(
- symbols,
- symbols.size
- )
+ fun indexAll(symbols: Collection)
/**
- * Index the given symbols in batches.
+ * Index the given symbols asynchronously.
*
* @param symbols The symbols to index.
- * @param batchSize The number of symbols to index in each batch.
*/
- fun indexBatched(
- symbols: Collection,
- batchSize: Int = DefaultIndex.DEFAULT_PUT_BATCH_SIZE,
- async: Boolean = DEF_IS_ASYNC,
- )
+ fun indexAllAsync(symbols: Collection)
/**
- * Create a sub-index in this index.
+ * Create a sub-index in this index. The default implementation will throw an [UnsupportedOperationException].
*
- * @param name The name of the sub-index.
* @return The created sub-index.
*/
- fun createSubIndex(
- name: String,
- config: IndexConfig? = null
- ): IIndex
+ fun createSubIndex(
+ params: IIndexParams? = null
+ ): IIndex {
+ throw UnsupportedOperationException()
+ }
/**
* Delete the index.
diff --git a/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexFactory.kt b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexFactory.kt
new file mode 100644
index 000000000..5d90387e0
--- /dev/null
+++ b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexFactory.kt
@@ -0,0 +1,161 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing
+
+import com.itsaky.androidide.utils.ServiceLoader
+
+/**
+ * A factory for creating instances of [IIndex].
+ *
+ * @param I The indexable type.
+ * @param P The index creation params.
+ * @author Akash Yadav
+ */
+interface IIndexFactory {
+
+ /**
+ * The parameters used to create the index.
+ */
+ var params: P?
+
+ /**
+ * Get the indexable type for the index.
+ */
+ fun indexableType(): Class
+
+ /**
+ * Get the parameter type for the index.
+ */
+ fun paramType(): Class
+
+ /**
+ * Create the index.
+ *
+ * @return The created [IIndex].
+ */
+ @Throws(NotFoundException::class)
+ fun create(): IIndex
+
+ companion object {
+
+ private val factoryCache =
+ mutableMapOf, IIndexFactory>()
+
+ /**
+ * Finds the index factory for the given symbol type returning `null` if not found.
+ *
+ * @param symTyp The symbol type.
+ * @param paramTyp The parameter type.
+ * @return The index factory.
+ */
+ fun findFactoryForSymType(
+ symTyp: Class,
+ paramTyp: Class? = null
+ ) = __findFactoryForSymType(symTyp = symTyp, paramTyp = paramTyp, fail = false)
+
+ /**
+ * Get the index factory for the given symbol type failing if not found.
+ *
+ * @param symTyp The symbol type.
+ * @param paramTyp The parameter type.
+ * @return The index factory.
+ */
+ fun getFactoryForSymType(
+ symTyp: Class,
+ paramTyp: Class? = null
+ ) = __findFactoryForSymType(symTyp = symTyp, paramTyp = paramTyp, fail = true)!!
+
+ /**
+ * Finds an index factory for the given symbol type.
+ *
+ * @param symTyp The symbol type.
+ * @param paramTyp The parameter type.
+ * @param fail Whether to fail if no factory is found.
+ * @return The index factory.
+ */
+ @Suppress("UNCHECKED_CAST", "FunctionName")
+ private fun __findFactoryForSymType(
+ symTyp: Class,
+ paramTyp: Class?,
+ fail: Boolean = true
+ ): IIndexFactory? {
+ var factory: IIndexFactory? = this.factoryCache[symTyp] as IIndexFactory?
+ if (factory != null) {
+ return factory
+ }
+
+ val impls = ServiceLoader.load(symTyp).iterator()
+ while (impls.hasNext()) {
+ val impl = impls.next()
+ if (impl is IIndexFactory<*, *> && symTyp == impl.indexableType()) {
+ if (factory == null) {
+ factory = impl as IIndexFactory
+ continue
+ }
+
+ if (!fail) {
+ return null
+ }
+
+ throw MultipleFactoriesException(symTyp)
+ }
+ }
+
+ if (factory != null && paramTyp != null && factory.paramType() != paramTyp) {
+ if (!fail) {
+ return null
+ }
+ throw InvalidParamTypeException(factory, paramTyp)
+ }
+
+ if (factory == null) {
+ if (!fail) {
+ return null
+ }
+
+ throw NotFoundException(symTyp)
+ }
+
+ val typ = factory.indexableType()
+
+ factoryCache.put(typ, factory)?.also {
+ throw IllegalStateException("Invalid cache state")
+ }
+
+ return factory
+ }
+ }
+
+ /**
+ * Exception thrown when an [IIndexFactory] cannot be found.
+ */
+ class NotFoundException(sym: Class) :
+ RuntimeException("No index factory found for ${sym.name}")
+
+ /**
+ * Exception thrown when multiple [IIndexFactory]s are found for a single symbol type.
+ */
+ class MultipleFactoriesException(sym: Class) :
+ RuntimeException("Multiple index factories found for ${sym.name}")
+
+ /**
+ * Exception thrown when the index parameters of a factory are of invalid type.
+ */
+ class InvalidParamTypeException(factory: IIndexFactory<*, *>, paramTyp: Class) :
+ RuntimeException("Factory ${factory.javaClass} expected parameters of type ${factory.paramType()} but an instance of $paramTyp was provided")
+}
\ No newline at end of file
diff --git a/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexParams.kt b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexParams.kt
new file mode 100644
index 000000000..72334e44b
--- /dev/null
+++ b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexParams.kt
@@ -0,0 +1,25 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing
+
+/**
+ * Index configuration
+ *
+ * @author Akash Yadav
+ */
+interface IIndexParams
\ No newline at end of file
diff --git a/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexService.kt b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexService.kt
new file mode 100644
index 000000000..87c44237e
--- /dev/null
+++ b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexService.kt
@@ -0,0 +1,48 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing
+
+import com.itsaky.androidide.progress.IProgressIndicator
+import com.itsaky.androidide.projects.api.Project
+import kotlinx.coroutines.Deferred
+import java.io.File
+
+/**
+ * An index service is responsible for indexing symbols.
+ *
+ * @author Akash Yadav
+ */
+interface IIndexService {
+
+ /**
+ * Called to scan files that need to be indexed by this index service.
+ *
+ * @param project The root project model which can be used to query the project properties.
+ * @return A [Deferred] collection of files that need to be indexed.
+ */
+ fun scanFiles(project: Project): Collection
+
+ /**
+ * Called to index the given files.
+ *
+ * @param project The root project model which can be used to query the project properties.
+ * @param progress An [IProgressIndicator] to report progress of the indexing process.
+ * @param files The files to index.
+ */
+ suspend fun indexFiles(project: Project, progress: IProgressIndicator, files: Collection)
+}
\ No newline at end of file
diff --git a/core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndexable.kt b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexable.kt
similarity index 100%
rename from core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndexable.kt
rename to core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexable.kt
diff --git a/core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndexer.kt b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexerParams.kt
similarity index 52%
rename from core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndexer.kt
rename to core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexerParams.kt
index 150af9906..c71548d09 100644
--- a/core/indexing/src/main/java/com/itsaky/androidide/indexing/IIndexer.kt
+++ b/core/indexing-api/src/main/java/com/itsaky/androidide/indexing/IIndexerParams.kt
@@ -17,32 +17,15 @@
package com.itsaky.androidide.indexing
-import kotlinx.coroutines.Deferred
-
/**
- * An indexer is responsible for indexing symbols.
+ * Parameters for [IIndexService].
*
* @author Akash Yadav
*/
-interface IIndexer : AutoCloseable {
+interface IIndexerParams {
/**
- * The path of the index. This does not represent the actual path in the file system, but rather the path
- * that will be used to uniquely identify the index.
+ * Parameters for the index.
*/
- val indexPath: String
-
- /**
- * Perform the indexing in the given index.
- *
- * @param index The index to perform the indexing in.
- * @param params The parameters for the indexing.
- * @return The collection of deferred results.
- */
- fun index(index: IIndex, params: Params): Collection>
-
- /**
- * The parameters for the indexer.
- */
- interface Params
+ val indexParams: ParamsT
}
\ No newline at end of file
diff --git a/core/indexing-core/.gitignore b/core/indexing-core/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/core/indexing-core/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/core/indexing-core/build.gradle.kts b/core/indexing-core/build.gradle.kts
new file mode 100644
index 000000000..ef00bab3e
--- /dev/null
+++ b/core/indexing-core/build.gradle.kts
@@ -0,0 +1,47 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+import com.itsaky.androidide.build.config.BuildConfig
+
+plugins {
+ id("com.android.library")
+ id("kotlin-android")
+ id("kotlin-kapt")
+ id("realm-android")
+}
+
+groupConfig {
+ groupIdSuffix.set("core")
+}
+
+android {
+ namespace = "${BuildConfig.packageName}.indexing.core"
+}
+
+dependencies {
+ kapt(libs.google.auto.service)
+ implementation(libs.google.auto.service.annotations)
+
+ api(libs.composite.jaxp)
+
+ api(projects.core.common)
+ api(projects.core.indexingApi)
+ api(projects.logging.logger)
+ api(projects.utilities.shared)
+
+ testImplementation(projects.testing.unitTest)
+}
\ No newline at end of file
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsIndexFactory.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsIndexFactory.kt
new file mode 100644
index 000000000..ae5d928da
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsIndexFactory.kt
@@ -0,0 +1,44 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.internal.platform
+
+import com.google.auto.service.AutoService
+import com.itsaky.androidide.indexing.IIndex
+import com.itsaky.androidide.indexing.IIndexFactory
+import com.itsaky.androidide.indexing.core.platform.AbstractIndexFactory
+import com.itsaky.androidide.indexing.core.platform.ClassOrMemberInfo
+import com.itsaky.androidide.indexing.core.platform.IApiVersionsIndex.Params
+
+/**
+ * @author Akash Yadav
+ */
+@AutoService(IIndexFactory::class)
+internal class ApiVersionsIndexFactory : AbstractIndexFactory() {
+
+ override fun indexableType(): Class {
+ return ClassOrMemberInfo::class.java
+ }
+
+ override fun paramType(): Class {
+ return Params::class.java
+ }
+
+ override fun create(): IIndex {
+ return ApiVersionsIndexImpl.newInstance(params)
+ }
+}
\ No newline at end of file
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsIndexImpl.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsIndexImpl.kt
new file mode 100644
index 000000000..2e320881a
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsIndexImpl.kt
@@ -0,0 +1,51 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.internal.platform
+
+import com.itsaky.androidide.db.IRealmProvider
+import com.itsaky.androidide.indexing.AbstractDBIndex
+import com.itsaky.androidide.indexing.core.platform.ClassOrMemberInfo
+import com.itsaky.androidide.indexing.core.platform.IApiVersionsIndex
+import com.itsaky.androidide.indexing.core.platform.IPlatformIndex
+import io.realm.Realm
+
+/**
+ * Index to store [ClassOrMemberInfo].
+ *
+ * @author Akash Yadav
+ */
+internal class ApiVersionsIndexImpl private constructor(params: IApiVersionsIndex.Params?) :
+ AbstractDBIndex(params),
+ IApiVersionsIndex {
+
+ companion object {
+ private const val NAME = "member-info"
+ private val PATH = IRealmProvider.createPath(IPlatformIndex.PLATFORM_INDEX_BASE_PATH, NAME)
+
+ @JvmStatic
+ fun newInstance(params: IApiVersionsIndex.Params?) = ApiVersionsIndexImpl(params)
+ }
+
+ override val name: String = NAME
+ override val path: String = PATH
+
+ override val realm: Realm by lazy {
+ val provider = IRealmProvider.instance()
+ provider.get(path)
+ }
+}
\ No newline at end of file
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfoParser.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsParser.kt
similarity index 68%
rename from java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfoParser.kt
rename to core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsParser.kt
index cdcad65c7..fce8d95c8 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfoParser.kt
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/ApiVersionsParser.kt
@@ -15,9 +15,10 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.lsp.java.indexing.apiinfo
+package com.itsaky.androidide.indexing.core.internal.platform
import androidx.collection.mutableIntObjectMapOf
+import com.itsaky.androidide.indexing.core.platform.ApiVersion
import jaxp.xml.namespace.QName
import jaxp.xml.stream.XMLInputFactory
import jaxp.xml.stream.events.Attribute
@@ -27,20 +28,26 @@ import org.slf4j.LoggerFactory
import java.io.InputStream
/**
- * Parser for parsing `api-versions.xml` file from the Android SDK and building [ApiInfo] models.
+ * Parser for parsing `api-versions.xml` file from the Android SDK and building [ApiVersion] models.
*
* @author Akash Yadav
*/
-class ApiInfoParser {
+open class ApiVersionsParser {
- private val apiInfos = mutableIntObjectMapOf()
- private val apiInfo = HashMap>>()
+ // A cache to store the ApiVersion instances with different values
+ // For example, if two classes have the same value for `since`,
+ // 'removed' and 'deprecated', then the same ApiVersion instance
+ // will be used for the two classes.
+ // The keys in this map are the packed (bitwise ORed) values of the three version integers.
+ // The first 8 bits are 0, the next 8 bits represent 'since', the next 8 bits represent 'deprecated'
+ // and the last 8 bits represent 'removed'.
+ private val apiInfosCache = mutableIntObjectMapOf()
private var apiVersion: Int? = null
private var currentClass: String? = null
companion object {
- private val log = LoggerFactory.getLogger(ApiInfoParser::class.java)
+ private val log = LoggerFactory.getLogger(ApiVersionsParser::class.java)
}
fun parse(apiVersionsXml: InputStream) {
@@ -65,32 +72,6 @@ class ApiInfoParser {
}
}
- /**
- * Returns [ApiInfo] for the given class.
- */
- fun getClassInfo(className: String): ApiInfo? {
- return apiInfo[className]?.first
- }
-
- /**
- * Returns [ApiInfo] for the given class and member.
- */
- fun getMemberInfo(className: String, memberName: String): ApiInfo? {
- return apiInfo[className]?.second?.get(memberName)
- }
-
- /**
- * Removes and returns the [ApiInfo] for the given class and member. This also removes the [ApiInfo]
- * for the class if the all the members of the class have been removed.
- */
- fun removeMemberInfo(className: String, memberName: String): ApiInfo? {
- return apiInfo[className]?.second?.remove(memberName).also {
- if (apiInfo[className]?.second?.isEmpty() == true) {
- apiInfo.remove(className)
- }
- }
- }
-
private fun consumeStartElement(event: StartElement) {
when (event.name.localPart) {
"api" -> apiVersion = event.getAttributeByName(QName("version")).value.toInt()
@@ -110,32 +91,51 @@ class ApiInfoParser {
}
val (name, versions) = event.parseAttrs()
- check(!apiInfo.containsKey(name)) {
+ check(!isDuplicateClass(name)) {
"Duplicate class entry: $name"
}
- val apiInfo = apiInfos.getOrPut(versions) {
+ val apiInfo = apiInfosCache.getOrPut(versions) {
createApiInfo(versions)
}
- this.apiInfo[name] = apiInfo to HashMap()
+ consumeClassVersionInfo(name, apiInfo)
this.currentClass = name
}
+ /**
+ * Check if the given class name is a duplicate.
+ */
+ protected open fun isDuplicateClass(name: String): Boolean {
+ return false
+ }
+
+ protected open fun consumeClassVersionInfo(name: String, apiVersion: ApiVersion) {}
+
private fun consumeMember(event: StartElement, memberType: String) {
val (name, versions) = event.parseAttrs()
val currentClass = checkNotNull(currentClass) {
"<${memberType}> element must be inside element"
}
- check(!apiInfo.containsKey(name)) {
+ check(!isDuplicateMember(currentClass, name)) {
"Duplicate $memberType entry in class $currentClass: $name"
}
+ consumeMemberVersionInfo(currentClass, name, memberType, createApiInfo(versions))
+ }
- val (_, members) = apiInfo[currentClass]!!
- val existing = members.put(name, createApiInfo(versions))
- check(existing == null) {
- "Duplicate $memberType entry in class $currentClass: $name"
- }
+ /**
+ * Check if the given member of the given class is a duplicate.
+ */
+ protected open fun isDuplicateMember(className: String, memberName: String): Boolean {
+ return false
+ }
+
+ protected open fun consumeMemberVersionInfo(
+ className: String,
+ member: String,
+ memberType: String,
+ apiVersion: ApiVersion
+ ) {
}
private fun consumeEndElement(element: EndElement) {
@@ -171,14 +171,14 @@ class ApiInfoParser {
"Invalid version: $since, $deprecated, $removed"
}
- val version = (since shl 16) + (deprecated shl 8) + removed
+ val version = (since shl 16) or (deprecated shl 8) or removed
return name!! to version
}
- private fun createApiInfo(versions: Int): ApiInfo {
+ private fun createApiInfo(versions: Int): ApiVersion {
val since = (versions shr 16) and 0x000000FF
val deprecated = (versions shr 8) and 0x000000FF
val removed = versions and 0x000000FF
- return ApiInfo.newInstance(since = since, deprecatedIn = deprecated, removedIn = removed)
+ return ApiVersion.newInstance(since = since, deprecatedIn = deprecated, removedIn = removed)
}
}
\ No newline at end of file
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/PlatformIndexService.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/PlatformIndexService.kt
new file mode 100644
index 000000000..af3fdb3f4
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/internal/platform/PlatformIndexService.kt
@@ -0,0 +1,47 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.internal.platform
+
+import com.google.auto.service.AutoService
+import com.itsaky.androidide.indexing.IIndexService
+import com.itsaky.androidide.progress.IProgressIndicator
+import com.itsaky.androidide.projects.api.Project
+import java.io.File
+
+/**
+ * @author Akash Yadav
+ */
+@AutoService(IIndexService::class)
+internal class PlatformIndexService : IIndexService {
+
+ override fun scanFiles(project: Project): Collection {
+ return mutableListOf().apply {
+ project.findAndroidModules().forEach { androidModule ->
+ add(androidModule.getPlatformDir() ?: return@forEach)
+ }
+ }
+ }
+
+ override suspend fun indexFiles(
+ project: Project,
+ progress: IProgressIndicator,
+ files: Collection
+ ) {
+ TODO("Not yet implemented")
+ }
+}
\ No newline at end of file
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/AbstractIndexFactory.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/AbstractIndexFactory.kt
new file mode 100644
index 000000000..9675deab7
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/AbstractIndexFactory.kt
@@ -0,0 +1,32 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.platform
+
+import com.itsaky.androidide.indexing.IIndexFactory
+import com.itsaky.androidide.indexing.IIndexParams
+import com.itsaky.androidide.indexing.IIndexable
+
+/**
+ * Abstract implementation of the [IIndexFactory].
+ *
+ * @author Akash Yadav
+ */
+abstract class AbstractIndexFactory : IIndexFactory {
+
+ override var params: P? = null
+}
\ No newline at end of file
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfo.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/ApiVersion.kt
similarity index 78%
rename from java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfo.kt
rename to core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/ApiVersion.kt
index 04b7e968d..0ccbe0714 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfo.kt
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/ApiVersion.kt
@@ -15,11 +15,11 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.lsp.java.indexing.apiinfo
+package com.itsaky.androidide.indexing.core.platform
import com.google.common.base.Objects
-import com.itsaky.androidide.lsp.java.indexing.ICloneable
-import com.itsaky.androidide.lsp.java.indexing.ISharedJavaIndexable
+import com.itsaky.androidide.indexing.IIndexable
+import com.itsaky.androidide.models.ICloneable
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.annotations.RealmField
@@ -33,12 +33,12 @@ import io.realm.annotations.Required
*/
@RealmClass
-open class ApiInfo : ISharedJavaIndexable, ICloneable {
+open class ApiVersion : IIndexable, ICloneable {
@Required
@PrimaryKey
@RealmField("id")
- override var id: Int? = null
+ var id: Int? = null
@RealmField("since")
var since: Int = 1
@@ -52,17 +52,17 @@ open class ApiInfo : ISharedJavaIndexable, ICloneable {
var removedIn: Int = 0
private set
- override fun computeId() {
+ private fun computeId() {
this.id = Objects.hashCode(this.since, this.removedIn, this.deprecatedIn)
}
/**
- * Update the API information from the given [ApiInfo].
+ * Update the API information from the given [ApiVersion].
*/
- fun update(apiInfo: ApiInfo) = apply {
- this.since = apiInfo.since
- this.deprecatedIn = apiInfo.deprecatedIn
- this.removedIn = apiInfo.removedIn
+ fun update(apiVersion: ApiVersion) = apply {
+ this.since = apiVersion.since
+ this.deprecatedIn = apiVersion.deprecatedIn
+ this.removedIn = apiVersion.removedIn
this.computeId()
}
@@ -82,7 +82,7 @@ open class ApiInfo : ISharedJavaIndexable, ICloneable {
override fun equals(other: Any?): Boolean {
if (this === other) return true
- if (other !is ApiInfo) return false
+ if (other !is ApiVersion) return false
if (id != other.id) return false
if (since != other.since) return false
@@ -101,17 +101,17 @@ open class ApiInfo : ISharedJavaIndexable, ICloneable {
}
override fun toString(): String {
- return "ApiInfo(id=$id, since=$since, deprecatedIn=$deprecatedIn, removedIn=$removedIn)"
+ return "ApiVersion(id=$id, since=$since, deprecatedIn=$deprecatedIn, removedIn=$removedIn)"
}
- override fun clone(): ApiInfo {
+ override fun clone(): ApiVersion {
return newInstance(since, deprecatedIn, removedIn)
}
companion object {
@JvmStatic
- fun newInstance(since: Int, deprecatedIn: Int, removedIn: Int): ApiInfo {
- return ApiInfo().apply {
+ fun newInstance(since: Int, deprecatedIn: Int, removedIn: Int): ApiVersion {
+ return ApiVersion().apply {
this.since = since
this.deprecatedIn = deprecatedIn
this.removedIn = removedIn
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/ClassOrMemberInfo.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/ClassOrMemberInfo.kt
new file mode 100644
index 000000000..cbf01f1b9
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/ClassOrMemberInfo.kt
@@ -0,0 +1,49 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.platform
+
+import io.realm.annotations.RealmField
+import io.realm.annotations.Required
+
+/**
+ * [ApiVersion] of a class or class members.
+ *
+ * @property className The fully qualified name of the class.
+ * @property memberName The name of the member (optional). Must be set if the objects represents API
+ * information about a member of a class. Otherwise, it could be `null`.
+ * @property apiVersion The [ApiVersion] about the class or the member.
+ *
+ * @author Akash Yadav
+ */
+open class ClassOrMemberInfo : IPlatformIndexable {
+
+ @Required
+ @RealmField("className")
+ var className: String? = null
+
+ @Required
+ @RealmField("memberName")
+ var memberName: String? = null
+
+ @Required
+ @RealmField("apiVersion")
+ var apiVersion: ApiVersion? = null
+
+ fun isMember(): Boolean = !isClass()
+ fun isClass(): Boolean = this.memberName == null
+}
\ No newline at end of file
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IApiVersionsIndex.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IApiVersionsIndex.kt
new file mode 100644
index 000000000..344126c44
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IApiVersionsIndex.kt
@@ -0,0 +1,34 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.platform
+
+import com.itsaky.androidide.indexing.IIndexParams
+import com.itsaky.androidide.indexing.core.platform.IApiVersionsIndex.Params
+
+/**
+ * Index which provides access to the API versions informations (`api-versions.xml`) from the
+ * Android SDK.
+ *
+ * @author Akash Yadav
+ */
+interface IApiVersionsIndex : IPlatformIndex {
+
+ class Params(
+ val platformId: String
+ ) : IIndexParams
+}
\ No newline at end of file
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IPlatformIndex.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IPlatformIndex.kt
new file mode 100644
index 000000000..d4aa51e1b
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IPlatformIndex.kt
@@ -0,0 +1,38 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.platform
+
+import com.itsaky.androidide.db.IRealmProvider
+import com.itsaky.androidide.indexing.IIndex
+import com.itsaky.androidide.indexing.IIndexParams
+
+/**
+ * Index for data available in the Android Platform SDK.
+ *
+ * @author Akash Yadav
+ */
+interface IPlatformIndex : IIndex {
+
+ companion object {
+
+ /**
+ * Base path for the platform index.
+ */
+ val PLATFORM_INDEX_BASE_PATH = IRealmProvider.createPath(IIndex.INDEX_BASE_PATH, "platform")
+ }
+}
\ No newline at end of file
diff --git a/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IPlatformIndexable.kt b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IPlatformIndexable.kt
new file mode 100644
index 000000000..17f4ffc0a
--- /dev/null
+++ b/core/indexing-core/src/main/java/com/itsaky/androidide/indexing/core/platform/IPlatformIndexable.kt
@@ -0,0 +1,27 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.platform
+
+import com.itsaky.androidide.indexing.IIndexable
+
+/**
+ * Symbols that are indexed in the [IPlatformIndex].
+ *
+ * @author Akash Yadav
+ */
+interface IPlatformIndexable : IIndexable
\ No newline at end of file
diff --git a/java/lsp/src/test/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfoParserTest.kt b/core/indexing-core/src/test/java/com/itsaky/androidide/indexing/core/platform/ApiVersionParserTest.kt
similarity index 93%
rename from java/lsp/src/test/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfoParserTest.kt
rename to core/indexing-core/src/test/java/com/itsaky/androidide/indexing/core/platform/ApiVersionParserTest.kt
index 85b176b29..8f2d8a507 100644
--- a/java/lsp/src/test/java/com/itsaky/androidide/lsp/java/indexing/apiinfo/ApiInfoParserTest.kt
+++ b/core/indexing-core/src/test/java/com/itsaky/androidide/indexing/core/platform/ApiVersionParserTest.kt
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.lsp.java.indexing.apiinfo
+package com.itsaky.androidide.indexing.core.platform
import com.google.common.truth.Truth.assertThat
import com.itsaky.androidide.testing.common.utils.findAndroidHome
@@ -32,7 +32,7 @@ import java.io.File
* @author Akash Yadav
*/
@RunWith(RobolectricTestRunner::class)
-class ApiInfoParserTest {
+class ApiVersionParserTest {
val apiVersionXml by lazy {
val platformsDir = File(findAndroidHome(), "platforms")
@@ -44,11 +44,11 @@ class ApiInfoParserTest {
platformDir.resolve("data/api-versions.xml")
}
- private lateinit var parser: ApiInfoParser
+ private lateinit var parser: CollectingApiVersionsParser
@Before
fun setup() {
- parser = ApiInfoParser()
+ parser = CollectingApiVersionsParser()
}
@Test
@@ -71,7 +71,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
parser.parse(inputStream)
val classInfo = parser.getClassInfo("com.example.ClassA")
@@ -93,7 +93,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
parser.parse(inputStream)
val classInfo = parser.getClassInfo("com.example.ClassA")
@@ -119,7 +119,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
parser.parse(inputStream)
val classAInfo = parser.getClassInfo("com.example.ClassA")
@@ -140,7 +140,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
parser.parse(inputStream)
val classInfo = parser.getClassInfo("com.example.ClassA")
@@ -159,7 +159,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
try {
parser.parse(inputStream)
assertThat(true).isFalse() // Should not reach here
@@ -177,7 +177,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
try {
parser.parse(inputStream)
assertThat(true).isFalse() // Should not reach here
@@ -196,7 +196,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
try {
parser.parse(inputStream)
assertThat(true).isFalse() // Should not reach here
@@ -217,7 +217,7 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
try {
parser.parse(inputStream)
assertThat(true).isFalse() // Should not reach here
@@ -238,8 +238,11 @@ class ApiInfoParserTest {
""".trimIndent()
val inputStream = ByteArrayInputStream(xml.toByteArray())
- val parser = ApiInfoParser()
- assertThrows("The markup in the document following the root element must be well-formed.", XMLStreamException::class.java) {
+ val parser = CollectingApiVersionsParser()
+ assertThrows(
+ "The markup in the document following the root element must be well-formed.",
+ XMLStreamException::class.java
+ ) {
parser.parse(inputStream)
}
}
@@ -328,7 +331,7 @@ class ApiInfoParserTest {
xmlBuilder.append("")
val inputStream = ByteArrayInputStream(xmlBuilder.toString().toByteArray())
- val parser = ApiInfoParser()
+ val parser = CollectingApiVersionsParser()
parser.parse(inputStream)
for (i in 1..1000) {
diff --git a/core/indexing-core/src/test/java/com/itsaky/androidide/indexing/core/platform/CollectingApiVersionsParser.kt b/core/indexing-core/src/test/java/com/itsaky/androidide/indexing/core/platform/CollectingApiVersionsParser.kt
new file mode 100644
index 000000000..f34548c8f
--- /dev/null
+++ b/core/indexing-core/src/test/java/com/itsaky/androidide/indexing/core/platform/CollectingApiVersionsParser.kt
@@ -0,0 +1,79 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.indexing.core.platform
+
+import com.itsaky.androidide.indexing.core.internal.platform.ApiVersionsParser
+
+/**
+ * @author Akash Yadav
+ */
+class CollectingApiVersionsParser : ApiVersionsParser() {
+
+ private val apiInfo = mutableMapOf>>()
+
+ override fun isDuplicateClass(name: String): Boolean {
+ return apiInfo.containsKey(name)
+ }
+
+ override fun consumeClassVersionInfo(name: String, apiVersion: ApiVersion) {
+ this.apiInfo[name] = apiVersion to HashMap()
+ }
+
+ override fun isDuplicateMember(className: String, memberName: String): Boolean {
+ return apiInfo[className]?.second?.containsKey(memberName) == true
+ }
+
+ override fun consumeMemberVersionInfo(
+ className: String,
+ member: String,
+ memberType: String,
+ apiVersion: ApiVersion
+ ) {
+ val (_, members) = apiInfo[className]!!
+ val existing = members.put(member, apiVersion)
+ check(existing == null) {
+ "Duplicate $memberType entry in class $className: $member"
+ }
+ }
+
+ /**
+ * Returns [ApiVersion] for the given class.
+ */
+ fun getClassInfo(className: String): ApiVersion? {
+ return apiInfo[className]?.first
+ }
+
+ /**
+ * Returns [ApiVersion] for the given class and member.
+ */
+ fun getMemberInfo(className: String, memberName: String): ApiVersion? {
+ return apiInfo[className]?.second?.get(memberName)
+ }
+
+ /**
+ * Removes and returns the [ApiVersion] for the given class and member. This also removes the [ApiVersion]
+ * for the class if the all the members of the class have been removed.
+ */
+ fun removeMemberInfo(className: String, memberName: String): ApiVersion? {
+ return apiInfo[className]?.second?.remove(memberName).also {
+ if (apiInfo[className]?.second?.isEmpty() == true) {
+ apiInfo.remove(className)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/indexing/src/main/java/com/itsaky/androidide/indexing/IndexProvider.kt b/core/indexing/src/main/java/com/itsaky/androidide/indexing/IndexProvider.kt
deleted file mode 100644
index 5d8fcfc3c..000000000
--- a/core/indexing/src/main/java/com/itsaky/androidide/indexing/IndexProvider.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file is part of AndroidIDE.
- *
- * AndroidIDE is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * AndroidIDE is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with AndroidIDE. If not, see .
- */
-
-package com.itsaky.androidide.indexing
-
-import com.itsaky.androidide.db.IRealmProvider
-import com.itsaky.androidide.db.IRealmProvider.Companion.PATH_SEPARATOR
-import com.itsaky.androidide.indexing.internal.DefaultIndex
-import io.realm.RealmConfiguration
-
-/**
- * The [IndexProvider] provides APIs to index symbols in a database.
- *
- * @author itsaky
- */
-object IndexProvider {
-
- const val INDEX_BASE_PATH = "${PATH_SEPARATOR}indexes"
-
- /**
- * Get the index for the given indexable type in the root path.
- *
- * @param T The indexable type.
- * @param config The index configuration.
- * @param name The internal path of the index.
- */
- fun getRootIndex(
- name: String,
- config: IndexConfig? = null
- ): IIndex {
- require(name.indexOf(PATH_SEPARATOR) == -1)
- return getIndexForPath("${PATH_SEPARATOR}${name}", config)
- }
-
- /**
- * Get the index for the given indexable type.
- *
- * @param path The internal path of the index.
- * @param config The index configuration.
- */
- fun getIndexForPath(
- path: String,
- config: IndexConfig? = null
- ): IIndex {
- val sepIdx = path.indexOfLast { it == PATH_SEPARATOR }
- val name = if (sepIdx > 0) path.substring(sepIdx + 1) else path
- val provider = IRealmProvider.instance()
- val realm = provider.get("${INDEX_BASE_PATH}${path}", config)
- val index = DefaultIndex.create(name, path, realm)
- return index
- }
-}
-
-/**
- * The [IndexConfig] is used to configure the index.
- */
-typealias IndexConfig = RealmConfiguration.Builder.() -> Unit
diff --git a/core/indexing/src/main/java/com/itsaky/androidide/indexing/internal/DefaultIndex.kt b/core/indexing/src/main/java/com/itsaky/androidide/indexing/internal/DefaultIndex.kt
deleted file mode 100644
index eef4333c0..000000000
--- a/core/indexing/src/main/java/com/itsaky/androidide/indexing/internal/DefaultIndex.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This file is part of AndroidIDE.
- *
- * AndroidIDE is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * AndroidIDE is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with AndroidIDE. If not, see .
- */
-
-package com.itsaky.androidide.indexing.internal
-
-import com.itsaky.androidide.indexing.IIndex
-import com.itsaky.androidide.indexing.IIndexable
-import com.itsaky.androidide.indexing.IndexConfig
-import com.itsaky.androidide.indexing.IndexProvider
-import io.realm.Realm
-import org.slf4j.LoggerFactory
-
-/**
- * Default implementation of [IIndex].
- *
- * @author Akash Yadav
- */
-class DefaultIndex private constructor(
- override val name: String,
- override val path: String,
- private val realm: Realm,
-) : IIndex {
-
- companion object {
- private val log = LoggerFactory.getLogger(DefaultIndex::class.java)
- const val DEFAULT_PUT_BATCH_SIZE = 100
-
- /**
- * Creates a new [IIndex] instance.
- */
- fun create(
- name: String,
- path: String,
- realm: Realm,
- ): IIndex {
- return DefaultIndex(name, path, realm)
- }
- }
-
-// override fun query(condition: QueryCondition): Query {
-// return box.query(condition).build()
-// }
-
- override fun index(symbol: IndexableT, async: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun indexBatched(symbols: Collection, batchSize: Int, async: Boolean) {
- TODO("Not yet implemented")
- }
-
- override fun createSubIndex(
- name: String,
- config: IndexConfig?
- ): IIndex {
- return IndexProvider.getIndexForPath(IIndex.createIndexPath(this.path, name), config)
- }
-
- override fun delete() {
- TODO("Not yet implemented")
- }
-}
\ No newline at end of file
diff --git a/core/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt b/core/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt
index ea03c16fa..db48a1312 100644
--- a/core/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt
+++ b/core/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt
@@ -113,8 +113,10 @@ class ProjectManagerImpl : IProjectManager, EventReceiver {
androidBuildVariants = buildVariants
}
- log.info("Found {} project sync issues: {}", rootProject.projectSyncIssues.syncIssues.size,
- rootProject.projectSyncIssues.syncIssues)
+ log.info(
+ "Found {} project sync issues: {}", rootProject.projectSyncIssues.syncIssues.size,
+ rootProject.projectSyncIssues.syncIssues
+ )
withStopWatch("Setup project") {
val indexerScope = CoroutineScope(Dispatchers.Default)
@@ -227,7 +229,8 @@ class ProjectManagerImpl : IProjectManager, EventReceiver {
val variant = module.getSelectedVariant()
if (variant == null) {
log.error(
- "Selected build variant for project '{}' not found", module.path)
+ "Selected build variant for project '{}' not found", module.path
+ )
return@flatMap emptyList()
}
diff --git a/core/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt b/core/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt
index ca0c29d4b..3494bd813 100644
--- a/core/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt
+++ b/core/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt
@@ -163,8 +163,10 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
override fun getSourceDirectories(): Set {
if (mainSourceSet == null) {
- log.warn("No main source set is available for project {}. Cannot get source directories.",
- name)
+ log.warn(
+ "No main source set is available for project {}. Cannot get source directories.",
+ name
+ )
return mutableSetOf()
}
@@ -256,7 +258,8 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
// Read resources in parallel
withStopWatch("Read resources for module : $path") {
val resourceReaderScope = CoroutineScope(
- Dispatchers.IO + CoroutineName("ResourceReader($path)"))
+ Dispatchers.IO + CoroutineName("ResourceReader($path)")
+ )
val resourceFlow = flow {
emit(getFrameworkResourceTable())
@@ -361,8 +364,8 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
libraryMap.values
.filter { library ->
library.type == ANDROID_LIBRARY &&
- library.androidLibraryData!!.resFolder.exists() &&
- library.findPackageName() != UNKNOWN_PACKAGE
+ library.androidLibraryData!!.resFolder.exists() &&
+ library.findPackageName() != UNKNOWN_PACKAGE
}
.also { libs -> deps = libs.size }
.mapNotNull { library ->
@@ -493,19 +496,26 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
val info = projectManager.androidBuildVariants[this.path]
if (info == null) {
log.error(
- "Failed to find selected build variant for module: '{}'", this.path)
+ "Failed to find selected build variant for module: '{}'", this.path
+ )
return null
}
val variant = this.getVariant(info.selectedVariant)
if (variant == null) {
log.error(
- "Build variant with name '{}' not found.", info.selectedVariant)
+ "Build variant with name '{}' not found.", info.selectedVariant
+ )
return null
}
return variant
}
- private fun getPlatformDir() = bootClassPaths.firstOrNull { it.name == "android.jar" }?.parentFile
+ /**
+ * Get the Android SDK platform directory for this Android module.
+ *
+ * @return The Android SDK platform directory for this Android module, or `null` if none is found.
+ */
+ fun getPlatformDir() = bootClassPaths.firstOrNull { it.name == "android.jar" }?.parentFile
}
diff --git a/java/lsp/build.gradle.kts b/java/lsp/build.gradle.kts
index 0d0a0d418..d68b77d75 100644
--- a/java/lsp/build.gradle.kts
+++ b/java/lsp/build.gradle.kts
@@ -46,21 +46,24 @@ kapt {
dependencies {
kapt(projects.annotation.processors)
+ kapt(libs.google.auto.service)
implementation(libs.androidide.ts)
implementation(libs.androidide.ts.java)
+ implementation(libs.androidx.annotation)
implementation(libs.androidx.appcompat)
implementation(libs.common.editor)
implementation(libs.common.javaparser)
implementation(libs.common.utilcode)
- implementation(libs.androidx.annotation)
+
+ implementation(libs.google.auto.service.annotations)
implementation(libs.google.guava)
implementation(libs.google.gson)
implementation(libs.google.material)
implementation(projects.core.actions)
implementation(projects.core.common)
- implementation(projects.core.indexing)
+ implementation(projects.core.indexingApi)
implementation(projects.core.lspApi)
implementation(projects.core.resources)
implementation(projects.editor.api)
@@ -80,4 +83,4 @@ dependencies {
androidTestImplementation(projects.testing.androidTest)
androidTestImplementation(projects.utilities.shared)
-}
\ No newline at end of file
+}
diff --git a/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaClassCRUDTest.kt b/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaClassCRUDTest.kt
index e039e7a79..458ee380b 100644
--- a/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaClassCRUDTest.kt
+++ b/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaClassCRUDTest.kt
@@ -20,7 +20,6 @@ package com.itsaky.androidide.lsp.java.indexing
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.itsaky.androidide.lsp.java.indexing.classfile.JavaClass
-import com.itsaky.androidide.lsp.java.indexing.classfile.JavaIndexingRealmModule
import com.itsaky.androidide.lsp.java.indexing.classfile.JavaType
import com.itsaky.androidide.testing.android.rules.RealmDBTestRule
import io.realm.RealmList
diff --git a/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexerTest.kt b/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexerTest.kt
index 32c1a3333..e746f7d59 100644
--- a/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexerTest.kt
+++ b/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexerTest.kt
@@ -22,7 +22,6 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.blankj.utilcode.util.ConvertUtils
import com.google.common.truth.Truth
-import com.itsaky.androidide.lsp.java.indexing.classfile.JavaIndexingRealmModule
import com.itsaky.androidide.testing.android.rules.RealmDBTestRule
import io.realm.RealmModel
import org.junit.Rule
diff --git a/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/SharedModelCRUDTest.kt b/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/SharedModelCRUDTest.kt
index c87955129..30d8c59e8 100644
--- a/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/SharedModelCRUDTest.kt
+++ b/java/lsp/src/androidTest/java/com/itsaky/androidide/lsp/java/indexing/SharedModelCRUDTest.kt
@@ -19,13 +19,12 @@ package com.itsaky.androidide.lsp.java.indexing
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
+import com.itsaky.androidide.indexing.core.platform.ApiInfo
import com.itsaky.androidide.lsp.java.indexing.classfile.ArrayAnnotationElementValue
import com.itsaky.androidide.lsp.java.indexing.classfile.ClassAnnotationElementValue
import com.itsaky.androidide.lsp.java.indexing.classfile.EnumAnnotationElementValue
import com.itsaky.androidide.lsp.java.indexing.classfile.IAnnotationElementValue
import com.itsaky.androidide.lsp.java.indexing.classfile.JavaConstant
-import com.itsaky.androidide.lsp.java.indexing.classfile.JavaIndexingRealmModule
import com.itsaky.androidide.lsp.java.indexing.classfile.JavaType
import com.itsaky.androidide.lsp.java.indexing.classfile.PrimitiveAnnotationElementValue
import com.itsaky.androidide.testing.android.rules.RealmDBTestRule
@@ -49,7 +48,7 @@ class SharedModelCRUDTest {
@Test
fun testApiInfoCreate() {
dbTestRule.withDb("api-info") {
- val apiInfo = ApiInfo.newInstance(since = 1, deprecatedIn = 21, removedIn = 23)
+ val apiInfo = com.itsaky.androidide.indexing.core.platform.ApiInfo.newInstance(since = 1, deprecatedIn = 21, removedIn = 23)
assertInsertUnique(apiInfo)
val apiInfo2 = apiInfo.clone().update(removedIn = 26)
@@ -63,7 +62,7 @@ class SharedModelCRUDTest {
@Test(expected = RealmPrimaryKeyConstraintException::class)
fun testApiInfoDuplicationError() {
dbTestRule.withDb("api-info-duplication-error") {
- val apiInfo = ApiInfo.newInstance(since = 1, deprecatedIn = 21, removedIn = 23)
+ val apiInfo = com.itsaky.androidide.indexing.core.platform.ApiInfo.newInstance(since = 1, deprecatedIn = 21, removedIn = 23)
assertInsertSingle(apiInfo)
assertInsertSingle(apiInfo)
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/IJavaSymbol.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/IJavaSymbol.kt
index 457665f37..07ebb9f2e 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/IJavaSymbol.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/IJavaSymbol.kt
@@ -17,8 +17,6 @@
package com.itsaky.androidide.lsp.java.indexing
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
-
/**
* A java symbol.
*
@@ -28,5 +26,4 @@ import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
*/
interface IJavaSymbol : IJavaIndexable {
var accessFlags: Int
- var apiInfo: ApiInfo?
}
\ No newline at end of file
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexer.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexer.kt
deleted file mode 100644
index 8e1d8d3e3..000000000
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexer.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * This file is part of AndroidIDE.
- *
- * AndroidIDE is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * AndroidIDE is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with AndroidIDE. If not, see .
- */
-
-package com.itsaky.androidide.lsp.java.indexing
-
-import com.itsaky.androidide.indexing.IIndex
-import com.itsaky.androidide.indexing.IIndexer
-import com.itsaky.androidide.indexing.IIndexer.Params
-import com.itsaky.androidide.tasks.cancelIfActive
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.async
-import java.io.File
-
-/**
- * @author Akash Yadav
- */
-class JavaIndexer(
- private val jarPaths: List
-) : IIndexer {
-
- companion object {
- const val INDEX_PATH = "/java"
- }
-
- private val coroutineScope = CoroutineScope(Dispatchers.IO)
- override val indexPath: String = INDEX_PATH
-
- override fun index(index: IIndex, params: Params): Collection> {
- return jarPaths.map { jar ->
- coroutineScope.async {
- val worker = JavaJarModelBuilder(jar)
-// worker.index(index)
- }
- }
- }
-
- override fun close() {
- coroutineScope.cancelIfActive("Cancellation requested")
- }
-}
\ No newline at end of file
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaIndexingRealmModule.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexingRealmModule.kt
similarity index 54%
rename from java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaIndexingRealmModule.kt
rename to java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexingRealmModule.kt
index dffd0a4c7..14f5b8931 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaIndexingRealmModule.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaIndexingRealmModule.kt
@@ -15,9 +15,22 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.lsp.java.indexing.classfile
+package com.itsaky.androidide.lsp.java.indexing
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
+import com.itsaky.androidide.lsp.java.indexing.classfile.AnnotationAnnotationElementValue
+import com.itsaky.androidide.lsp.java.indexing.classfile.AnnotationElement
+import com.itsaky.androidide.lsp.java.indexing.classfile.ArrayAnnotationElementValue
+import com.itsaky.androidide.lsp.java.indexing.classfile.ClassAnnotationElementValue
+import com.itsaky.androidide.lsp.java.indexing.classfile.EnumAnnotationElementValue
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaAnnotation
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaClass
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaConstant
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaEnum
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaField
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaInterface
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaMethod
+import com.itsaky.androidide.lsp.java.indexing.classfile.JavaType
+import com.itsaky.androidide.lsp.java.indexing.classfile.PrimitiveAnnotationElementValue
import io.realm.annotations.RealmModule
/**
@@ -33,7 +46,6 @@ import io.realm.annotations.RealmModule
ClassAnnotationElementValue::class,
EnumAnnotationElementValue::class,
PrimitiveAnnotationElementValue::class,
- ApiInfo::class,
JavaAnnotation::class,
JavaClass::class,
JavaConstant::class,
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaJarModelBuilder.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaJarModelBuilder.kt
index f0c5459d4..a70038026 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaJarModelBuilder.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/JavaJarModelBuilder.kt
@@ -269,17 +269,18 @@ class JavaJarModelBuilder(private val jar: File) {
val methodName = method.getName(classFile.constant_pool)
val methodType = DescriptorUtils.returnType(descriptor)
- add(this@setAnnotationElements.newAnnotationElement(
- methodName, methodType, method.access_flags.flags
- ).apply {
- val annotationDefault =
- method.attributes.get(Attribute.AnnotationDefault) as? AnnotationDefault_attribute?
- if (annotationDefault != null) {
- val defaultValue = annotationDefault.default_value
- val value = toAnnotationElementValue(defaultValue, classFile)
- this.defaultValue = value.let(RealmAny::valueOf) ?: RealmAny.nullValue()
- }
- })
+ add(
+ newAnnotationElement(
+ methodName, methodType, method.access_flags.flags
+ ).apply {
+ val annotationDefault =
+ method.attributes.get(Attribute.AnnotationDefault) as? AnnotationDefault_attribute?
+ if (annotationDefault != null) {
+ val defaultValue = annotationDefault.default_value
+ val value = toAnnotationElementValue(defaultValue, classFile)
+ this.defaultValue = value.let(RealmAny::valueOf) ?: RealmAny.nullValue()
+ }
+ })
}
}
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/AnnotationElement.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/AnnotationElement.kt
index 5c542769c..f0fe17bdc 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/AnnotationElement.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/AnnotationElement.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.itsaky.androidide.lsp.java.indexing.IJavaSymbol
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
import io.realm.RealmAny
import io.realm.RealmResults
import io.realm.annotations.Index
@@ -47,9 +46,6 @@ open class AnnotationElement : IJavaSymbol {
@RealmField("accessFlags")
override var accessFlags: Int = 0
- @RealmField("apiInfo")
- override var apiInfo: ApiInfo? = null
-
@LinkingObjects("methods")
val ofClass: RealmResults? = null
@@ -78,18 +74,16 @@ open class AnnotationElement : IJavaSymbol {
companion object {
@JvmStatic
- fun JavaAnnotation.newAnnotationElement(
+ fun newAnnotationElement(
name: String,
type: JavaType,
accessFlags: Int,
- apiInfo: ApiInfo? = null,
defaultValue: RealmAny? = null
): AnnotationElement {
return AnnotationElement().apply {
this.name = name
this.type = type
this.accessFlags = accessFlags
- this.apiInfo = apiInfo
this.defaultValue = defaultValue
}
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaAnnotation.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaAnnotation.kt
index a997d04af..4a3a7d4a2 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaAnnotation.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaAnnotation.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.itsaky.androidide.lsp.java.indexing.IJavaType
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
import io.realm.RealmList
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
@@ -66,9 +65,6 @@ open class JavaAnnotation : IJavaType {
@RealmField("accessFlags")
override var accessFlags: Int = 0
- @RealmField("apiInfo")
- override var apiInfo: ApiInfo? = null
-
@RealmField("fields")
override var fields: RealmList? = null
@@ -90,7 +86,6 @@ open class JavaAnnotation : IJavaType {
accessFlags: Int,
isInner: Boolean = false,
superInterfacesFqn: RealmList? = null,
- apiInfo: ApiInfo? = null,
fields: RealmList? = null,
methods: RealmList? = null
): JavaAnnotation {
@@ -102,7 +97,6 @@ open class JavaAnnotation : IJavaType {
this.superClassFqn = superClassFqn
this.superInterfacesFqn = superInterfacesFqn
this.accessFlags = accessFlags
- this.apiInfo = apiInfo
this.fields = fields
this.methods = methods
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaClass.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaClass.kt
index 80e1e138d..8fcde79eb 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaClass.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaClass.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.itsaky.androidide.lsp.java.indexing.IJavaType
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
import io.realm.RealmList
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
@@ -61,9 +60,6 @@ open class JavaClass : IJavaType {
@RealmField("accessFlags")
override var accessFlags: Int = 0
- @RealmField("apiInfo")
- override var apiInfo: ApiInfo? = null
-
@RealmField("fields")
override var fields: RealmList? = null
@@ -83,7 +79,6 @@ open class JavaClass : IJavaType {
isInner: Boolean = false,
superClassFqn: String? = null,
superInterfacesFqn: RealmList? = null,
- apiInfo: ApiInfo? = null,
fields: RealmList? = null,
methods: RealmList? = null
): JavaClass {
@@ -95,7 +90,6 @@ open class JavaClass : IJavaType {
this.superClassFqn = superClassFqn
this.superInterfacesFqn = superInterfacesFqn
this.accessFlags = accessFlags
- this.apiInfo = apiInfo
this.fields = fields
this.methods = methods
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaEnum.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaEnum.kt
index 0d654f392..78d9ca644 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaEnum.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaEnum.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.itsaky.androidide.lsp.java.indexing.IJavaType
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
import io.realm.RealmList
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
@@ -60,9 +59,6 @@ open class JavaEnum : IJavaType {
@RealmField("accessFlags")
override var accessFlags: Int = 0
- @RealmField("apiInfo")
- override var apiInfo: ApiInfo? = null
-
@RealmField("fields")
override var fields: RealmList? = null
@@ -82,7 +78,6 @@ open class JavaEnum : IJavaType {
isInner: Boolean = false,
superClassFqn: String? = null,
superInterfacesFqn: RealmList? = null,
- apiInfo: ApiInfo? = null,
fields: RealmList? = null,
methods: RealmList? = null
): JavaEnum {
@@ -94,7 +89,6 @@ open class JavaEnum : IJavaType {
this.superClassFqn = superClassFqn
this.superInterfacesFqn = superInterfacesFqn
this.accessFlags = accessFlags
- this.apiInfo = apiInfo
this.fields = fields
this.methods = methods
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaField.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaField.kt
index 9bce4e299..b1b809ffa 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaField.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaField.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.itsaky.androidide.lsp.java.indexing.IJavaSymbol
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
import io.realm.RealmResults
import io.realm.annotations.Index
import io.realm.annotations.LinkingObjects
@@ -41,9 +40,6 @@ open class JavaField : IJavaSymbol {
@RealmField("accessFlags")
override var accessFlags: Int = 0
- @RealmField("apiInfo")
- override var apiInfo: ApiInfo? = null
-
@RealmField("constantValue")
var constantValue: JavaConstant? = null
@@ -56,14 +52,12 @@ open class JavaField : IJavaSymbol {
name: String,
type: JavaType,
accessFlags: Int,
- apiInfo: ApiInfo? = null,
constantValue: JavaConstant? = null
): JavaField {
return JavaField().apply {
this.name = name
this.type = type
this.accessFlags = accessFlags
- this.apiInfo = apiInfo
this.constantValue = constantValue
}
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaInterface.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaInterface.kt
index c7185778c..130e055cf 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaInterface.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaInterface.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.itsaky.androidide.lsp.java.indexing.IJavaType
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
import io.realm.RealmList
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
@@ -61,9 +60,6 @@ open class JavaInterface : IJavaType {
@RealmField("accessFlags")
override var accessFlags: Int = 0
- @RealmField("apiInfo")
- override var apiInfo: ApiInfo? = null
-
@RealmField("fields")
override var fields: RealmList? = null
@@ -82,7 +78,6 @@ open class JavaInterface : IJavaType {
accessFlags: Int,
isInner: Boolean = false,
superInterfacesFqn: RealmList? = null,
- apiInfo: ApiInfo? = null,
fields: RealmList? = null,
methods: RealmList? = null
): JavaInterface {
@@ -93,7 +88,6 @@ open class JavaInterface : IJavaType {
this.isInner = isInner
this.superInterfacesFqn = superInterfacesFqn
this.accessFlags = accessFlags
- this.apiInfo = apiInfo
this.fields = fields
this.methods = methods
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaMethod.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaMethod.kt
index c5542ba6c..69635b067 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaMethod.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaMethod.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.itsaky.androidide.lsp.java.indexing.IJavaSymbol
-import com.itsaky.androidide.lsp.java.indexing.apiinfo.ApiInfo
import io.realm.RealmList
import io.realm.RealmResults
import io.realm.annotations.Index
@@ -47,9 +46,6 @@ open class JavaMethod : IJavaSymbol {
@RealmField("accessFlags")
override var accessFlags: Int = 0
- @RealmField("apiInfo")
- override var apiInfo: ApiInfo? = null
-
@LinkingObjects("methods")
val ofClass: RealmResults? = null
@@ -75,14 +71,12 @@ open class JavaMethod : IJavaSymbol {
paramsTypes: RealmList,
returnType: JavaType,
accessFlags: Int,
- apiInfo: ApiInfo? = null,
): JavaMethod {
return JavaMethod().apply {
this.name = name
this.paramsTypes = paramsTypes
this.returnType = returnType
this.accessFlags = accessFlags
- this.apiInfo = apiInfo
}
}
}
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaType.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaType.kt
index bb1290bf4..206529d25 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaType.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/JavaType.kt
@@ -18,8 +18,8 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.google.common.base.Objects
-import com.itsaky.androidide.lsp.java.indexing.ICloneable
import com.itsaky.androidide.lsp.java.indexing.ISharedJavaIndexable
+import com.itsaky.androidide.models.ICloneable
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@@ -146,7 +146,7 @@ open class JavaType : ISharedJavaIndexable, ICloneable {
override fun toString(): String {
return "JavaType(id=$id, name=$name, kind=$kind, arrayDims=$arrayDims)"
}
-
+
companion object {
const val KIND_UNKNOWN = -1
const val KIND_BOOLEAN = 0
@@ -163,7 +163,7 @@ open class JavaType : ISharedJavaIndexable, ICloneable {
// kind values used in IAnnotationElementValue
// defined here for convenience
internal const val __KIND_STRING = 10
- internal const val __KIND_CLASS = 11
+ internal const val __KIND_CLASS = 11
internal const val __KIND_ENUM = 12
internal const val __KIND_ANNOTATION = 13
internal const val __KIND_ARRAY = 14
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/annotationElementValues.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/annotationElementValues.kt
index ac30e1706..743352a7a 100644
--- a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/annotationElementValues.kt
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/classfile/annotationElementValues.kt
@@ -18,8 +18,8 @@
package com.itsaky.androidide.lsp.java.indexing.classfile
import com.google.common.base.Objects
-import com.itsaky.androidide.db.utils.isEqualTo
import com.itsaky.androidide.db.utils.hash
+import com.itsaky.androidide.db.utils.isEqualTo
import com.itsaky.androidide.lsp.java.indexing.ISharedJavaIndexable
import io.realm.RealmAny
import io.realm.RealmDictionary
diff --git a/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/internal/JavaIndexServiceImpl.kt b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/internal/JavaIndexServiceImpl.kt
new file mode 100644
index 000000000..533ef1db3
--- /dev/null
+++ b/java/lsp/src/main/java/com/itsaky/androidide/lsp/java/indexing/internal/JavaIndexServiceImpl.kt
@@ -0,0 +1,42 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.lsp.java.indexing.internal
+
+import com.google.auto.service.AutoService
+import com.itsaky.androidide.indexing.IIndexService
+import com.itsaky.androidide.progress.IProgressIndicator
+import com.itsaky.androidide.projects.api.Project
+import java.io.File
+
+/**
+ * @author Akash Yadav
+ */
+@AutoService(IIndexService::class)
+internal class JavaIndexServiceImpl : IIndexService {
+
+ override fun scanFiles(project: Project): Collection {
+ return emptySet()
+ }
+
+ override suspend fun indexFiles(
+ project: Project,
+ progress: IProgressIndicator,
+ files: Collection
+ ) {
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d1a8b7f86..cb0bcab4d 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -127,7 +127,8 @@ include(
":core:app",
":core:common",
":core:database",
- ":core:indexing",
+ ":core:indexing-api",
+ ":core:indexing-core",
":core:lsp-api",
":core:lsp-models",
":core:projects",
diff --git a/testing/benchmarks/build.gradle.kts b/testing/benchmarks/build.gradle.kts
index ccf535e39..1a30a2b45 100644
--- a/testing/benchmarks/build.gradle.kts
+++ b/testing/benchmarks/build.gradle.kts
@@ -68,7 +68,7 @@ dependencies {
androidTestImplementation(projects.core.common)
androidTestImplementation(projects.core.database)
- androidTestImplementation(projects.core.indexing)
+ androidTestImplementation(projects.core.indexingApi)
androidTestImplementation(projects.java.lsp)
androidTestImplementation(projects.utilities.shared)
-}
\ No newline at end of file
+}
diff --git a/utilities/shared/src/main/java/com/itsaky/androidide/progress/IProgressIndicator.kt b/utilities/shared/src/main/java/com/itsaky/androidide/progress/IProgressIndicator.kt
new file mode 100644
index 000000000..4f078da13
--- /dev/null
+++ b/utilities/shared/src/main/java/com/itsaky/androidide/progress/IProgressIndicator.kt
@@ -0,0 +1,45 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.progress
+
+import androidx.annotation.FloatRange
+
+/**
+ * A progress indicator reports progress of a specific task.
+ *
+ * @author Akash Yadav
+ */
+interface IProgressIndicator {
+
+ /**
+ * Called when the task begins its execution.
+ */
+ fun onStart()
+
+ /**
+ * Called each time the task progresses.
+ *
+ * @param progress The progress of the task. Must be a value between 0 (start) and 1 (finish).
+ */
+ fun onProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float)
+
+ /**
+ * Called when the task finishes its execution.
+ */
+ fun onFinish()
+}
\ No newline at end of file