diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt index 2de5e19f81d..904106fc1f4 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt @@ -138,6 +138,10 @@ private fun PsiElement.collectInfos(c: ModuleInfoCollector): T { return this.processLightElement(c) } + collectModuleInfoByUserData(this).firstOrNull()?.let { + return c.onResult(it) + } + val containingFile = containingFile ?: return c.onFailure("Analyzing element of type ${this::class.java} with no containing file\nText:\n$text") @@ -205,6 +209,8 @@ private inline fun collectInfosByVirtualFile( treatAsLibrarySource: Boolean, onOccurrence: (IdeaModuleInfo?) -> T ): T { + collectModuleInfoByUserData(project, virtualFile).map(onOccurrence) + val moduleRelatedModuleInfo = getModuleRelatedModuleInfo(project, virtualFile) if (moduleRelatedModuleInfo != null) { onOccurrence(moduleRelatedModuleInfo) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt new file mode 100644 index 00000000000..4e712eb4fe7 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt @@ -0,0 +1,17 @@ +package org.jetbrains.kotlin.idea.caches.project + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement + + +// NO-OP implementation, full implementation only for AS3.3, AS3.4 + +fun collectModuleInfoByUserData( + project: Project, + virtualFile: VirtualFile +): List = emptyList() + +fun collectModuleInfoByUserData( + psiElement: PsiElement +): List = emptyList() diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt.as33 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt.as33 new file mode 100644 index 00000000000..fab56a53b79 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt.as33 @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.project + +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleUtilCore +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.LIBRARY_KEY +import org.jetbrains.kotlin.idea.MODULE_ROOT_TYPE_KEY +import org.jetbrains.kotlin.idea.SDK_KEY +import org.jetbrains.kotlin.idea.caches.project.UserDataModuleContainer.ForPsiElement +import org.jetbrains.kotlin.idea.caches.project.UserDataModuleContainer.ForVirtualFile +import org.jetbrains.kotlin.idea.core.getSourceType +import org.jetbrains.kotlin.utils.addIfNotNull + +// This file declares non-exported API for overriding module info with user-data + + +private sealed class UserDataModuleContainer { + abstract fun getUserData(key: Key): T? + abstract fun getModule(): Module? + + data class ForVirtualFile(val virtualFile: VirtualFile, val project: Project) : UserDataModuleContainer() { + override fun getUserData(key: Key): T? = virtualFile.getUserData(key) + override fun getModule(): Module? = ModuleUtilCore.findModuleForFile(virtualFile, project) + } + + data class ForPsiElement(val psiElement: PsiElement) : UserDataModuleContainer() { + override fun getUserData(key: Key): T? { + return psiElement.getUserData(key) + ?: psiElement.containingFile?.getUserData(key) + ?: psiElement.containingFile?.originalFile?.virtualFile?.getUserData(key) + } + + override fun getModule(): Module? = ModuleUtilCore.findModuleForPsiElement(psiElement) + } +} + + +private fun collectModuleInfoByUserData( + project: Project, + container: UserDataModuleContainer +): List { + fun forModule(): ModuleSourceInfo? { + val rootType = container.getUserData(MODULE_ROOT_TYPE_KEY) ?: return null + val module = container.getModule() ?: return null + + return when (rootType.getSourceType()) { + null -> null + SourceType.PRODUCTION -> module.productionSourceInfo() + SourceType.TEST -> module.testSourceInfo() + } + } + + val result = mutableListOf() + result.addIfNotNull(forModule()) + + val library = container.getUserData(LIBRARY_KEY) + if (library != null) { + result.addAll(createLibraryInfo(project, library)) + } + + val sdk = container.getUserData(SDK_KEY) + if (sdk != null) { + result.add(SdkInfo(project, sdk)) + } + + return result +} + + +fun collectModuleInfoByUserData( + project: Project, + virtualFile: VirtualFile +): List = collectModuleInfoByUserData(project, ForVirtualFile(virtualFile, project)) + +fun collectModuleInfoByUserData( + psiElement: PsiElement +): List = collectModuleInfoByUserData(psiElement.project, ForPsiElement(psiElement)) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt.as34 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt.as34 new file mode 100644 index 00000000000..fab56a53b79 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/userDataModuleInfoUtil.kt.as34 @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.project + +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleUtilCore +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.LIBRARY_KEY +import org.jetbrains.kotlin.idea.MODULE_ROOT_TYPE_KEY +import org.jetbrains.kotlin.idea.SDK_KEY +import org.jetbrains.kotlin.idea.caches.project.UserDataModuleContainer.ForPsiElement +import org.jetbrains.kotlin.idea.caches.project.UserDataModuleContainer.ForVirtualFile +import org.jetbrains.kotlin.idea.core.getSourceType +import org.jetbrains.kotlin.utils.addIfNotNull + +// This file declares non-exported API for overriding module info with user-data + + +private sealed class UserDataModuleContainer { + abstract fun getUserData(key: Key): T? + abstract fun getModule(): Module? + + data class ForVirtualFile(val virtualFile: VirtualFile, val project: Project) : UserDataModuleContainer() { + override fun getUserData(key: Key): T? = virtualFile.getUserData(key) + override fun getModule(): Module? = ModuleUtilCore.findModuleForFile(virtualFile, project) + } + + data class ForPsiElement(val psiElement: PsiElement) : UserDataModuleContainer() { + override fun getUserData(key: Key): T? { + return psiElement.getUserData(key) + ?: psiElement.containingFile?.getUserData(key) + ?: psiElement.containingFile?.originalFile?.virtualFile?.getUserData(key) + } + + override fun getModule(): Module? = ModuleUtilCore.findModuleForPsiElement(psiElement) + } +} + + +private fun collectModuleInfoByUserData( + project: Project, + container: UserDataModuleContainer +): List { + fun forModule(): ModuleSourceInfo? { + val rootType = container.getUserData(MODULE_ROOT_TYPE_KEY) ?: return null + val module = container.getModule() ?: return null + + return when (rootType.getSourceType()) { + null -> null + SourceType.PRODUCTION -> module.productionSourceInfo() + SourceType.TEST -> module.testSourceInfo() + } + } + + val result = mutableListOf() + result.addIfNotNull(forModule()) + + val library = container.getUserData(LIBRARY_KEY) + if (library != null) { + result.addAll(createLibraryInfo(project, library)) + } + + val sdk = container.getUserData(SDK_KEY) + if (sdk != null) { + result.add(SdkInfo(project, sdk)) + } + + return result +} + + +fun collectModuleInfoByUserData( + project: Project, + virtualFile: VirtualFile +): List = collectModuleInfoByUserData(project, ForVirtualFile(virtualFile, project)) + +fun collectModuleInfoByUserData( + psiElement: PsiElement +): List = collectModuleInfoByUserData(psiElement.project, ForPsiElement(psiElement)) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/userDataModuleInfo.kt.as33 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/userDataModuleInfo.kt.as33 new file mode 100644 index 00000000000..f20bf8fc6cf --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/userDataModuleInfo.kt.as33 @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea + +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.util.Key +import org.jetbrains.jps.model.module.JpsModuleSourceRootType + +// WARNING, this API is used by AS3.3+ + + +const val LIBRARY_KEY_NAME = "Kt_Library" +const val SDK_KEY_NAME = "Kt_Sdk" +const val MODULE_ROOT_TYPE_KEY_NAME = "Kt_SourceRootType" + +@JvmField +val MODULE_ROOT_TYPE_KEY = getOrCreateKey>(MODULE_ROOT_TYPE_KEY_NAME) + +@JvmField +val SDK_KEY = getOrCreateKey(SDK_KEY_NAME) + +@JvmField +val LIBRARY_KEY = getOrCreateKey(LIBRARY_KEY_NAME) + + +inline fun getOrCreateKey(name: String): Key { + @Suppress("DEPRECATION", "UNCHECKED_CAST") + val existingKey = Key.findKeyByName(name) as Key? + return existingKey ?: Key.create(name) +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/userDataModuleInfo.kt.as34 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/userDataModuleInfo.kt.as34 new file mode 100644 index 00000000000..f20bf8fc6cf --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/userDataModuleInfo.kt.as34 @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea + +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.libraries.Library +import com.intellij.openapi.util.Key +import org.jetbrains.jps.model.module.JpsModuleSourceRootType + +// WARNING, this API is used by AS3.3+ + + +const val LIBRARY_KEY_NAME = "Kt_Library" +const val SDK_KEY_NAME = "Kt_Sdk" +const val MODULE_ROOT_TYPE_KEY_NAME = "Kt_SourceRootType" + +@JvmField +val MODULE_ROOT_TYPE_KEY = getOrCreateKey>(MODULE_ROOT_TYPE_KEY_NAME) + +@JvmField +val SDK_KEY = getOrCreateKey(SDK_KEY_NAME) + +@JvmField +val LIBRARY_KEY = getOrCreateKey(LIBRARY_KEY_NAME) + + +inline fun getOrCreateKey(name: String): Key { + @Suppress("DEPRECATION", "UNCHECKED_CAST") + val existingKey = Key.findKeyByName(name) as Key? + return existingKey ?: Key.create(name) +} diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt index 7d1ca89ed8c..445e679fc20 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt @@ -22,6 +22,19 @@ private val testRootTypes: Set> = setOf( KotlinResourceRootType.TestResource ) +private val sourceRootTypes = setOf>( + JavaSourceRootType.SOURCE, + JavaResourceRootType.RESOURCE, + KotlinSourceRootType.Source, + KotlinResourceRootType.Resource +) + +fun JpsModuleSourceRootType<*>.getSourceType(): SourceType? = when(this) { + in sourceRootTypes -> SourceType.PRODUCTION + in testRootTypes -> SourceType.TEST + else -> null +} + fun FileIndex.isInTestSourceContentKotlinAware(fileOrDir: VirtualFile) = isUnderSourceRootOfType(fileOrDir, testRootTypes) fun FileIndex.getSourceType(fileOrDir: VirtualFile): SourceType? = when {