diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt index e2b6da55f9b..708e0f129db 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptDefinition.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.parsing.KotlinParserDefinition import org.jetbrains.kotlin.psi.KtScript import java.io.File +import kotlin.comparisons.compareValues import kotlin.reflect.KClass import kotlin.script.templates.standard.ScriptTemplateWithArgs @@ -42,13 +43,33 @@ open class KotlinScriptDefinition(val template: KClass) { open fun getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? = null } -interface KotlinScriptExternalDependencies { +interface KotlinScriptExternalDependencies : Comparable { val javaHome: String? get() = null val classpath: Iterable get() = emptyList() val imports: Iterable get() = emptyList() val sources: Iterable get() = emptyList() val scripts: Iterable get() = emptyList() + + override fun compareTo(other: KotlinScriptExternalDependencies): Int = + compareValues(javaHome, other.javaHome) + .chainCompare { compareIterables(classpath, other.classpath) } + .chainCompare { compareIterables(imports, other.imports) } + .chainCompare { compareIterables(sources, other.sources) } + .chainCompare { compareIterables(scripts, other.scripts) } } object StandardScriptDefinition : KotlinScriptDefinition(ScriptTemplateWithArgs::class) +private fun> compareIterables(a: Iterable, b: Iterable): Int { + val ia = a.iterator() + val ib = b.iterator() + while (true) { + if (ia.hasNext() && !ib.hasNext()) return 1 + if (!ia.hasNext() && !ib.hasNext()) return 0 + if (!ia.hasNext()) return -1 + val compRes = compareValues(ia.next(), ib.next()) + if (compRes != 0) return compRes + } +} + +private inline fun Int.chainCompare(compFn: () -> Int ): Int = if (this != 0) this else compFn() \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index 9367dc6339c..65673e90ecf 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.context.GlobalContext import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.project.outOfBlockModificationCount @@ -52,6 +53,7 @@ import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.sumByLong import java.lang.AssertionError @@ -74,14 +76,14 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { } - private val facadesForScriptDependencies: SLRUCache = - object : SLRUCache(2, 3) { - override fun createValue(key: ComparableScriptDependencies?): ProjectResolutionFacade { + private val facadesForScriptDependencies: SLRUCache = + object : SLRUCache(2, 3) { + override fun createValue(key: KotlinScriptExternalDependencies?): ProjectResolutionFacade { return createFacadeForScriptDependencies(ScriptDependenciesModuleInfo(project, key)) } } - private fun getFacadeForScriptDependencies(dependencies: ComparableScriptDependencies?) = synchronized(facadesForScriptDependencies) { + private fun getFacadeForScriptDependencies(dependencies: KotlinScriptExternalDependencies?) = synchronized(facadesForScriptDependencies) { facadesForScriptDependencies.get(dependencies) } @@ -105,7 +107,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { //TODO: provide correct trackers dependencies = listOf( LibraryModificationTracker.getInstance(project), - ProjectRootModificationTracker.getInstance(project) + ProjectRootModificationTracker.getInstance(project), + ScriptDependenciesModificationTracker.getInstance(project) ), moduleFilter = { it == dependenciesModuleInfo }, syntheticFiles = syntheticFiles diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt index b4aae4f1957..f31c503d0c2 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.idea.caches.resolve import com.intellij.openapi.project.Project -import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.vfs.VirtualFile @@ -31,7 +30,6 @@ import org.jetbrains.kotlin.script.KotlinScriptDefinition import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies import org.jetbrains.kotlin.script.KotlinScriptExternalImportsProvider import org.jetbrains.kotlin.utils.singletonOrEmptyList -import java.io.File private val SCRIPT_NAME_PREFIX: String = "script " @@ -47,7 +45,7 @@ data class ScriptModuleInfo(val project: Project, val scriptFile: VirtualFile, get() = ModuleOrigin.OTHER val externalDependencies by lazy { - KotlinScriptExternalImportsProvider.getInstance(project)?.getExternalImports(scriptFile)?.makeComparable() + KotlinScriptExternalImportsProvider.getInstance(project)?.getExternalImports(scriptFile) } override val name: Name = Name.special("<$SCRIPT_NAME_PREFIX${scriptDefinition.name}>") @@ -75,29 +73,8 @@ fun findJdk(dependencies: KotlinScriptExternalDependencies?, project: Project): allJdks.firstOrNull() } -private inline fun tryGet(body: () -> T): T? { - return try { - body() - } - catch (e: Throwable) { - null - } -} - -data class ComparableScriptDependencies( - override val javaHome: String?, - override val classpath: Iterable, - override val imports: Iterable, - override val sources: Iterable, - override val scripts: Iterable -): KotlinScriptExternalDependencies - -fun KotlinScriptExternalDependencies.makeComparable() = ComparableScriptDependencies( - tryGet { javaHome }, classpath, imports, sources, tryGet { scripts } ?: listOf() -) - -class ScriptDependenciesModuleInfo(val project: Project, val dependencies: ComparableScriptDependencies?): IdeaModuleInfo { - override fun dependencies() = listOf(this) + sdkDependencies(dependencies, project) +class ScriptDependenciesModuleInfo(val project: Project, val dependencies: KotlinScriptExternalDependencies?): IdeaModuleInfo { + override fun dependencies() = (listOf(this) + sdkDependencies(dependencies, project)) override val name = Name.special("