Refactor and fixes after review
improving script constructor search algorithm - now default params should be supported remove prefix Customized- from scripts ModuleInfo-related classes refactoring ideaModuleInfos after review refactoring ResolveSessionProvider construction for readability refactoring KotlinScriptConfigurationManager after review fixing KotlinScriptDefinitionProvider after review
This commit is contained in:
+8
-2
@@ -317,8 +317,14 @@ object KotlinToJVMBytecodeCompiler {
|
||||
catch (e: java.lang.NoSuchMethodException) {
|
||||
for (ctor in scriptClass.kotlin.constructors) {
|
||||
val (ctorArgs, scriptArgsLeft) = ctor.parameters.fold(Pair(emptyList<Any>(), scriptArgs), ::foldingFunc)
|
||||
if (ctorArgs.size == ctor.parameters.size && (scriptArgsLeft == null || scriptArgsLeft.isEmpty()))
|
||||
return ctor.call(*ctorArgs.toTypedArray())
|
||||
if (ctorArgs.size <= ctor.parameters.size && (scriptArgsLeft == null || scriptArgsLeft.isEmpty())) {
|
||||
val argsMap = ctorArgs.zip(ctor.parameters) { a, p -> Pair(p, a) }.toMap()
|
||||
try {
|
||||
return ctor.callBy(argsMap)
|
||||
}
|
||||
catch (e: Exception) { // TODO: find the exact exception type thrown then callBy fails
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ private fun tryFindKotlinPathsForScriptClasspathEnvVars(project: Project): Kotli
|
||||
.map { it() }
|
||||
.firstOrNull { it.runtimePath.exists() }
|
||||
|
||||
private fun generateKotlinScriptClasspathEnvVarsFromPaths(project: Project, paths: KotlinPaths?): Map<String, List<String>> =
|
||||
fun generateKotlinScriptClasspathEnvVarsFromPaths(project: Project, paths: KotlinPaths?): Map<String, List<String>> =
|
||||
mapOf("kotlin-runtime" to (paths?.run { listOf(runtimePath.canonicalPath) } ?: emptyList()),
|
||||
"kotlin-reflect" to (paths?.run { listOf(reflectPath.canonicalPath) } ?: emptyList()),
|
||||
"project-root" to listOf(project.basePath ?: "."),
|
||||
|
||||
@@ -65,7 +65,9 @@ class KotlinScriptDefinitionProvider {
|
||||
}
|
||||
|
||||
fun removeScriptDefinition(scriptDefinition: KotlinScriptDefinition) {
|
||||
definitions.remove(scriptDefinition)
|
||||
definitionsLock.write {
|
||||
definitions.remove(scriptDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+12
-60
@@ -290,40 +290,40 @@ internal object NotUnderContentRootModuleInfo : IdeaModuleInfo {
|
||||
override fun dependencies(): List<IdeaModuleInfo> = listOf(this)
|
||||
}
|
||||
|
||||
class CustomizedScriptModuleSearchScope(val scriptFile: VirtualFile, baseScope: GlobalSearchScope) : DelegatingGlobalSearchScope(baseScope) {
|
||||
override fun equals(other: Any?) = other is CustomizedScriptModuleSearchScope && scriptFile == other.scriptFile && super.equals(other)
|
||||
class ScriptModuleSearchScope(val scriptFile: VirtualFile, baseScope: GlobalSearchScope) : DelegatingGlobalSearchScope(baseScope) {
|
||||
override fun equals(other: Any?) = other is ScriptModuleSearchScope && scriptFile == other.scriptFile && super.equals(other)
|
||||
|
||||
override fun hashCode() = scriptFile.hashCode() * 73 * super.hashCode()
|
||||
}
|
||||
|
||||
internal data class CustomizedScriptModuleInfo(val project: Project, val module: Module?, val virtualFile: VirtualFile,
|
||||
val scriptDefinition: KotlinScriptDefinition,
|
||||
val scriptExtraImports: List<KotlinScriptExtraImport>) : IdeaModuleInfo {
|
||||
internal data class ScriptModuleInfo(val project: Project, val module: Module?, val scriptFile: VirtualFile,
|
||||
val scriptDefinition: KotlinScriptDefinition,
|
||||
val scriptExtraImports: List<KotlinScriptExtraImport>) : IdeaModuleInfo {
|
||||
override val moduleOrigin: ModuleOrigin
|
||||
get() = ModuleOrigin.OTHER
|
||||
|
||||
override val name: Name = Name.special("<$SCRIPT_NAME_PREFIX${scriptDefinition.name}>")
|
||||
|
||||
override fun contentScope(): CustomizedScriptModuleSearchScope {
|
||||
override fun contentScope(): ScriptModuleSearchScope {
|
||||
val dependenciesRoots = dependenciesRoots()
|
||||
return CustomizedScriptModuleSearchScope(
|
||||
virtualFile,
|
||||
return ScriptModuleSearchScope(
|
||||
scriptFile,
|
||||
if (dependenciesRoots.isEmpty()) GlobalSearchScope.EMPTY_SCOPE
|
||||
else GlobalSearchScope.union(dependenciesRoots.map { FileLibraryScope(project, it) }.toTypedArray()))
|
||||
}
|
||||
|
||||
private fun dependenciesRoots(): List<VirtualFile> {
|
||||
// TODO: find out whether it should be cashed (some changes listener should be implemented for the cached roots)
|
||||
val virtualFileManager = VirtualFileManager.getInstance()
|
||||
val jarfs = StandardFileSystems.jar()
|
||||
return (scriptDefinition.getScriptDependenciesClasspath() + scriptExtraImports.flatMap { it.classpath })
|
||||
.map { File(it).canonicalFile }
|
||||
.distinct()
|
||||
.map {
|
||||
.mapNotNull {
|
||||
// TODO: ensure that the entries are checked elsewhere, so diagnostics is delivered to a user if files are not correctly specified
|
||||
if (it.isFile)
|
||||
jarfs.findFileByPath(it.absolutePath + URLUtil.JAR_SEPARATOR) ?: throw FileNotFoundException("Classpath entry points to a file that is not a JAR archive: ${it.canonicalPath}")
|
||||
jarfs.findFileByPath(it.absolutePath + URLUtil.JAR_SEPARATOR) ?: null // diag: Classpath entry points to a file that is not a JAR archive
|
||||
else
|
||||
virtualFileManager.findFileByUrl("file://${it.absolutePath}") ?: throw FileNotFoundException("Classpath entry points to a non-existent location: ${it.canonicalPath}")
|
||||
StandardFileSystems.local().findFileByPath(it.absolutePath) ?: null // diag: Classpath entry points to a non-existent location
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +337,6 @@ internal data class CustomizedScriptModuleInfo(val project: Project, val module:
|
||||
}
|
||||
|
||||
class FileLibraryScope(project: Project, private val libraryRoot: VirtualFile) : GlobalSearchScope(project) {
|
||||
val cachedEntries : MutableSet<VirtualFile> = hashSetOf()
|
||||
|
||||
override fun contains(file: VirtualFile): Boolean =
|
||||
VfsUtilCore.isAncestor(libraryRoot, file, false)
|
||||
@@ -353,53 +352,6 @@ class FileLibraryScope(project: Project, private val libraryRoot: VirtualFile) :
|
||||
override fun hashCode() = libraryRoot.hashCode()
|
||||
}
|
||||
|
||||
private data class FakeFileLibrary(val libraryRoot: VirtualFile) : Library {
|
||||
override fun getFiles(rootType: OrderRootType): Array<out VirtualFile> = arrayOf(libraryRoot)
|
||||
|
||||
override fun getUrls(rootType: OrderRootType): Array<out String> = arrayOf(libraryRoot.url)
|
||||
|
||||
override fun getName(): String? = libraryRoot.name
|
||||
|
||||
override fun getModifiableModel(): Library.ModifiableModel { throw UnsupportedOperationException() }
|
||||
|
||||
override fun getTable(): LibraryTable? = null
|
||||
|
||||
override fun getRootProvider(): RootProvider { throw UnsupportedOperationException() }
|
||||
|
||||
override fun isJarDirectory(url: String): Boolean { throw UnsupportedOperationException() }
|
||||
|
||||
override fun isJarDirectory(url: String, rootType: OrderRootType): Boolean { throw UnsupportedOperationException() }
|
||||
|
||||
override fun isValid(url: String, rootType: OrderRootType): Boolean { throw UnsupportedOperationException() }
|
||||
|
||||
override fun readExternal(element: Element?) { throw UnsupportedOperationException() }
|
||||
|
||||
override fun writeExternal(element: Element?) { throw UnsupportedOperationException() }
|
||||
|
||||
override fun dispose() { }
|
||||
}
|
||||
|
||||
private class FileLibraryModuleInfo(project: Project, val libraryRoot: VirtualFile) : LibraryInfo(project, FakeFileLibrary(libraryRoot)) {
|
||||
|
||||
override val moduleOrigin: ModuleOrigin
|
||||
get() = ModuleOrigin.OTHER
|
||||
|
||||
override val name: Name = Name.special("<$LIBRARY_NAME_PREFIX${libraryRoot.nameWithoutExtension}>")
|
||||
|
||||
override fun contentScope() = FileLibraryScope(project, libraryRoot)
|
||||
|
||||
override fun dependencies(): List<IdeaModuleInfo> = emptyList()
|
||||
|
||||
override fun toString() = "FileLibraryModuleInfo(root=${libraryRoot.name})"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
return (other is FileLibraryModuleInfo && libraryRoot == other.libraryRoot)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = 47 * libraryRoot.hashCode()
|
||||
}
|
||||
|
||||
private class LibraryWithoutSourceScope(project: Project, private val library: Library) :
|
||||
LibraryScopeBase(project, library.getFiles(OrderRootType.CLASSES), arrayOf<VirtualFile>()) {
|
||||
|
||||
|
||||
+25
-40
@@ -121,52 +121,46 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
|
||||
}
|
||||
val dependenciesForSyntheticFileCache = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, filesModificationTracker)
|
||||
val debugName = "completion/highlighting in $syntheticFileModule for files ${files.joinToString { it.name }} for platform $targetPlatform"
|
||||
|
||||
fun makeGlobalResolveSessionProvider(reuseDataFrom: ProjectResolutionFacade? = null,
|
||||
moduleFilter: (IdeaModuleInfo) -> Boolean = { true }
|
||||
): CachedValueProvider.Result<ModuleResolverProvider> {
|
||||
return globalResolveSessionProvider(
|
||||
debugName,
|
||||
project,
|
||||
targetPlatform,
|
||||
sdk,
|
||||
commonGlobalContext = globalContext,
|
||||
syntheticFiles = files,
|
||||
reuseDataFrom = reuseDataFrom,
|
||||
moduleFilter = moduleFilter,
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
)
|
||||
}
|
||||
|
||||
return when {
|
||||
syntheticFileModule is ModuleSourceInfo -> {
|
||||
val dependentModules = syntheticFileModule.getDependentModules()
|
||||
ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||
globalResolveSessionProvider(
|
||||
debugName,
|
||||
project,
|
||||
targetPlatform,
|
||||
sdk,
|
||||
commonGlobalContext = globalContext,
|
||||
syntheticFiles = files,
|
||||
makeGlobalResolveSessionProvider(
|
||||
reuseDataFrom = globalFacade(targetPlatform, sdk),
|
||||
moduleFilter = { it in dependentModules },
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
)
|
||||
moduleFilter = { it in dependentModules })
|
||||
}
|
||||
}
|
||||
|
||||
syntheticFileModule is CustomizedScriptModuleInfo -> {
|
||||
syntheticFileModule is ScriptModuleInfo -> {
|
||||
ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||
globalResolveSessionProvider(
|
||||
debugName,
|
||||
project,
|
||||
targetPlatform,
|
||||
sdk,
|
||||
commonGlobalContext = globalContext,
|
||||
syntheticFiles = files,
|
||||
reuseDataFrom = librariesFacade(targetPlatform, sdk),
|
||||
moduleFilter = { true },
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
makeGlobalResolveSessionProvider(
|
||||
reuseDataFrom = librariesFacade(targetPlatform, sdk)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> {
|
||||
ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||
globalResolveSessionProvider(
|
||||
debugName,
|
||||
project,
|
||||
targetPlatform,
|
||||
sdk,
|
||||
commonGlobalContext = globalContext,
|
||||
syntheticFiles = files,
|
||||
makeGlobalResolveSessionProvider(
|
||||
reuseDataFrom = librariesFacade(targetPlatform, sdk),
|
||||
moduleFilter = { it == syntheticFileModule },
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
moduleFilter = { it == syntheticFileModule }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -177,16 +171,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
|
||||
// (file under both classes and sources root)
|
||||
LOG.warn("Creating cache with synthetic files ($files) in classes of library $syntheticFileModule")
|
||||
ProjectResolutionFacade(project, globalContext.storageManager) {
|
||||
globalResolveSessionProvider(
|
||||
debugName,
|
||||
project,
|
||||
targetPlatform,
|
||||
sdk,
|
||||
commonGlobalContext = globalContext,
|
||||
syntheticFiles = files,
|
||||
moduleFilter = { true },
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
)
|
||||
makeGlobalResolveSessionProvider()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ private fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFil
|
||||
|
||||
val scriptDefinition = getScriptDefinition(virtualFile, project)
|
||||
if (scriptDefinition != null)
|
||||
return CustomizedScriptModuleInfo(project, module, virtualFile, scriptDefinition, getScriptExtraImports(virtualFile, project))
|
||||
return ScriptModuleInfo(project, module, virtualFile, scriptDefinition, getScriptExtraImports(virtualFile, project))
|
||||
|
||||
return NotUnderContentRootModuleInfo
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ fun getResolveScope(file: KtFile): GlobalSearchScope {
|
||||
|
||||
return when (file.getModuleInfo()) {
|
||||
is ModuleSourceInfo -> KotlinSourceFilterScope.sourceAndClassFiles(file.resolveScope, file.project)
|
||||
is CustomizedScriptModuleInfo -> file.getModuleInfo().contentScope()
|
||||
is ScriptModuleInfo -> file.getModuleInfo().contentScope()
|
||||
else -> GlobalSearchScope.EMPTY_SCOPE
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -30,6 +30,7 @@ import com.intellij.util.indexing.IndexableSetContributor
|
||||
import com.intellij.util.io.URLUtil
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.FileLibraryScope
|
||||
import org.jetbrains.kotlin.script.*
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.lang.ref.WeakReference
|
||||
@@ -44,7 +45,7 @@ class KotlinScriptConfigurationManager(project: Project,
|
||||
private val kotlinScriptDependenciesIndexableSetContributor: KotlinScriptDependenciesIndexableSetContributor?
|
||||
) : AbstractProjectComponent(project) {
|
||||
|
||||
private val kotlinEnvVars: Map<String, List<String>> by lazy { generateKotlinScriptClasspathEnvVars(myProject) }
|
||||
private val kotlinEnvVars: Map<String, List<String>> by lazy { generateKotlinScriptClasspathEnvVarsFromPaths(myProject, PathUtil.getKotlinPathsForIdeaPlugin()) }
|
||||
|
||||
init {
|
||||
reloadScriptDefinitions()
|
||||
@@ -57,7 +58,7 @@ class KotlinScriptConfigurationManager(project: Project,
|
||||
override fun after(events: List<VFileEvent>) {
|
||||
val changedExtraImportConfigs = ArrayList<VirtualFile>()
|
||||
var anyScriptDefinitionChanged = false
|
||||
events.filter { it is VFileEvent }.forEach {
|
||||
events.forEach {
|
||||
it.file?.let {
|
||||
if (isScriptDefinitionConfigFile(it)) {
|
||||
anyScriptDefinitionChanged = true
|
||||
@@ -155,10 +156,8 @@ class KotlinScriptConfigurationManager(project: Project,
|
||||
|
||||
class KotlinScriptDependenciesIndexableSetContributor : IndexableSetContributor() {
|
||||
|
||||
override fun getAdditionalProjectRootsToIndex(project: Project): Set<VirtualFile> {
|
||||
return super.getAdditionalProjectRootsToIndex(project) +
|
||||
KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspath()
|
||||
}
|
||||
override fun getAdditionalProjectRootsToIndex(project: Project): Set<VirtualFile> =
|
||||
KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspath().toSet()
|
||||
|
||||
override fun getAdditionalRootsToIndex(): Set<VirtualFile> = emptySet()
|
||||
}
|
||||
|
||||
+5
-6
@@ -25,11 +25,10 @@ import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.search.EverythingGlobalScope
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.CustomizedScriptModuleSearchScope
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ScriptModuleSearchScope
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinderImpl
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinSafeClassFinder
|
||||
|
||||
@Suppress("unused") // project extension
|
||||
class KotlinScriptDependenciesClassFinder(project: Project,
|
||||
private val kotlinScriptConfigurationManager: KotlinScriptConfigurationManager
|
||||
) : NonClasspathClassFinder(project), KotlinSafeClassFinder {
|
||||
@@ -46,8 +45,8 @@ class KotlinScriptDependenciesClassFinder(project: Project,
|
||||
override fun calcClassRoots(): List<VirtualFile> = kotlinScriptConfigurationManager.getAllScriptsClasspath()
|
||||
|
||||
override fun getCache(scope: GlobalSearchScope?): PackageDirectoryCache =
|
||||
(scope as? CustomizedScriptModuleSearchScope ?:
|
||||
(scope as? JavaClassFinderImpl.DelegatingGlobalSearchScopeWithBaseAccess)?.base as? CustomizedScriptModuleSearchScope
|
||||
(scope as? ScriptModuleSearchScope ?:
|
||||
(scope as? JavaClassFinderImpl.FilterOutKotlinSourceFilesScope)?.base as? ScriptModuleSearchScope
|
||||
)?.let {
|
||||
myCaches.get(it.scriptFile)
|
||||
} ?: super.getCache(scope)
|
||||
@@ -60,8 +59,8 @@ class KotlinScriptDependenciesClassFinder(project: Project,
|
||||
override fun findClass(qualifiedName: String, scope: GlobalSearchScope): PsiClass? =
|
||||
super.findClass(qualifiedName, scope)?.let { aClass ->
|
||||
when {
|
||||
scope is CustomizedScriptModuleSearchScope ||
|
||||
(scope as? JavaClassFinderImpl.DelegatingGlobalSearchScopeWithBaseAccess)?.base is CustomizedScriptModuleSearchScope ||
|
||||
scope is ScriptModuleSearchScope ||
|
||||
(scope as? JavaClassFinderImpl.FilterOutKotlinSourceFilesScope)?.base is ScriptModuleSearchScope ||
|
||||
scope is EverythingGlobalScope ||
|
||||
aClass.containingFile?.virtualFile.let { file ->
|
||||
file != null &&
|
||||
|
||||
Reference in New Issue
Block a user