diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfos.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfos.kt index cfd04545ae8..6f5f5913f37 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfos.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaModuleInfos.kt @@ -23,20 +23,28 @@ import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.* import com.intellij.openapi.roots.impl.libraries.LibraryEx import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.vfs.StandardFileSystems +import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.util.SmartList +import com.intellij.util.io.URLUtil import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.script.KotlinScriptDefinition import org.jetbrains.kotlin.utils.alwaysNull import org.jetbrains.kotlin.utils.emptyOrSingletonList +import java.io.File +import java.io.FileNotFoundException import java.lang.reflect.Method import java.util.* private val LIBRARY_NAME_PREFIX: String = "library " +private val SCRIPT_NAME_PREFIX: String = "script " // TODO used reflection to be compatible with IDEA from both 143 and 144 branches, // TODO switch to directly using when "since-build" will be >= 144.3357.4 @@ -271,6 +279,56 @@ internal object NotUnderContentRootModuleInfo : IdeaModuleInfo { override fun dependencies(): List = listOf(this) } +internal data class CustomizedScriptModuleInfo(val project: Project, val virtualFile: VirtualFile, val scriptDefinition: KotlinScriptDefinition) : IdeaModuleInfo { + override val moduleOrigin: ModuleOrigin + get() = ModuleOrigin.OTHER + + override val name: Name = Name.special("<$SCRIPT_NAME_PREFIX${scriptDefinition.name}>") + + override fun contentScope() = GlobalSearchScope.union(dependenciesRoots().map { FileLibraryScope(project, it) }.toTypedArray()) + + private fun dependenciesRoots(): List { + // TODO: find out whether it should be cashed + val virtualFileManager = VirtualFileManager.getInstance() + val jarfs = StandardFileSystems.jar() + return scriptDefinition.getScriptDependenciesClasspath().map { + if (File(it).isFile) + jarfs.findFileByPath(it + URLUtil.JAR_SEPARATOR) ?: throw FileNotFoundException("Classpath entry points to a file that is not a JAR archive: $it") + else + virtualFileManager.findFileByUrl("file://$it") ?: throw FileNotFoundException("Classpath entry points to a non-existent location: $it") + } + } + override fun dependencies(): List = listOf(this) +} + +private class FileLibraryScope(project: Project, private val libraryRoot: VirtualFile) : GlobalSearchScope(project) { + val cachedEntries : MutableSet = hashSetOf() + + override fun contains(file: VirtualFile): Boolean = + VfsUtilCore.isAncestor(libraryRoot, file, false) + + override fun isSearchInLibraries(): Boolean = true + override fun isSearchInModuleContent(aModule: Module): Boolean = false + + // TODO: check if this is a valid decision for the case of a single root + override fun compare(file1: VirtualFile, file2: VirtualFile): Int = 0 + + override fun equals(other: Any?) = other is FileLibraryScope && libraryRoot == other.libraryRoot + + override fun hashCode() = libraryRoot.hashCode() +} + +private class FileLibraryModuleInfo(val project: Project, val libraryRoot: VirtualFile) :IdeaModuleInfo { + override val moduleOrigin: ModuleOrigin + get() = ModuleOrigin.OTHER + + override val name: Name = Name.special(libraryRoot.nameWithoutExtension) + + override fun contentScope() = FileLibraryScope(project, libraryRoot) + + override fun dependencies(): List = emptyList() +} + private class LibraryWithoutSourceScope(project: Project, private val library: Library) : LibraryScopeBase(project, library.getFiles(OrderRootType.CLASSES), arrayOf()) { 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 f7a39912a0d..52e9b446c4a 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 @@ -139,6 +139,22 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { } } + syntheticFileModule is CustomizedScriptModuleInfo -> { + ProjectResolutionFacade(project, globalContext.storageManager) { + globalResolveSessionProvider( + debugName, + project, + targetPlatform, + sdk, + commonGlobalContext = globalContext, + syntheticFiles = files, + reuseDataFrom = librariesFacade(targetPlatform, sdk), + moduleFilter = { true }, + dependencies = dependenciesForSyntheticFileCache + ) + } + } + syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> { ProjectResolutionFacade(project, globalContext.storageManager) { globalResolveSessionProvider( diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/getModuleInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/getModuleInfo.kt index 8e44e3e47d2..5e1384b6973 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/getModuleInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/getModuleInfo.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.asJava.KtLightElement import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider import org.jetbrains.kotlin.utils.sure fun PsiElement.getModuleInfo(): IdeaModuleInfo = this.getModuleInfo { reason -> @@ -120,6 +121,11 @@ private fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFil } } } + + val scriptDefinition = KotlinScriptDefinitionProvider.getInstance(project).findScriptDefinition(virtualFile) + if (scriptDefinition != null) + return CustomizedScriptModuleInfo(project, virtualFile, scriptDefinition) + return NotUnderContentRootModuleInfo }