[kotlin] K2: refine script use scope handling and improve unused symbol detection

#KTIJ-34779

GitOrigin-RevId: 43d8e0a9ee09794e12b67fb72038d5f7a5c0e081
This commit is contained in:
Vlad Koshkin
2025-07-06 15:32:34 +00:00
committed by intellij-monorepo-bot
parent 852ab98792
commit 83d4ecc4a6
2 changed files with 16 additions and 5 deletions
@@ -1,8 +1,10 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.core.script.k2.navigation
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.DelegatingGlobalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.UseScopeEnlarger
import org.jetbrains.kotlin.psi.KtFile
@@ -10,6 +12,13 @@ import org.jetbrains.kotlin.psi.KtFile
class KotlinScriptUseScopeEnlarger : UseScopeEnlarger() {
override fun getAdditionalUseScope(element: PsiElement): SearchScope? {
val file = element.containingFile as? KtFile ?: return null
return if (file.isScript()) GlobalSearchScope.allScope(element.project) else null
return if (file.isScript()) ProjectFileByExtensionSearchScope(element.project, "kts") else null
}
}
private class ProjectFileByExtensionSearchScope(project: Project, private val extension: String) :
DelegatingGlobalSearchScope(projectScope(project)) {
override fun contains(file: VirtualFile): Boolean {
return super.contains(file) && file.extension == extension
}
}
}
@@ -61,7 +61,6 @@ import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.DataClassResolver
import org.jetbrains.kotlin.scripting.definitions.isScript
object K2UnusedSymbolUtil {
private val KOTLIN_ADDITIONAL_ANNOTATIONS: List<String> = listOf("kotlin.test.*", "kotlin.js.JsExport")
@@ -70,7 +69,7 @@ object K2UnusedSymbolUtil {
// Simple PSI-based checks
fun isApplicableByPsi(declaration: KtNamedDeclaration): Boolean {
if (declaration.containingFile.isScript()) return false
if (declaration.isScriptTopLevelPublicDeclaration()) return false
// never mark companion object as unused (there are too many reasons it can be needed for)
if (declaration is KtObjectDeclaration && declaration.isCompanion()) return false
@@ -135,6 +134,9 @@ object K2UnusedSymbolUtil {
return ownerFunction.containingClass()?.isInterface() == true
}
private fun KtNamedDeclaration.isScriptTopLevelPublicDeclaration(): Boolean
= parent.parent is KtScript && !hasModifier(KtTokens.PRIVATE_KEYWORD)
context(KaSession)
fun isHiddenFromResolution(declaration: KtNamedDeclaration): Boolean {
val anno = declaration.findAnnotation(