Do not run unused symbol inspection if declaration in used in more than 3 scripts

This commit is contained in:
Natalia Selezneva
2019-01-29 16:14:05 +03:00
parent c29332e290
commit 74909c4d09
2 changed files with 74 additions and 13 deletions
@@ -19,18 +19,27 @@ package org.jetbrains.kotlin.idea.search
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.FileTypeRegistry
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.FileIndexFacade
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.impl.cache.impl.id.IdIndex
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.PsiSearchHelper
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.Processor
import com.intellij.util.indexing.FileBasedIndex
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.util.compat.psiSearchHelperInstance
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.script.findScriptDefinition
import org.jetbrains.kotlin.types.expressions.OperatorConventions
infix fun SearchScope.and(otherScope: SearchScope): SearchScope = intersectWith(otherScope)
@@ -108,7 +117,36 @@ fun PsiSearchHelper.isCheapEnoughToSearchConsideringOperators(
fileToIgnoreOccurrencesIn: PsiFile?,
progress: ProgressIndicator?
): PsiSearchHelper.SearchCostResult {
if (OperatorConventions.isConventionName(Name.identifier(name))) return PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES
if (OperatorConventions.isConventionName(Name.identifier(name))) {
return PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES
}
if (!isCheapToSearchUsagesInScripts(scope.restrictToKotlinSources(), name)) {
return PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES
}
return isCheapEnoughToSearch(name, scope, fileToIgnoreOccurrencesIn, progress)
}
private fun isCheapToSearchUsagesInScripts(scope: GlobalSearchScope, name: String): Boolean {
val project = scope.project ?: return true
var scriptsCount = 0
val processor = object : Processor<VirtualFile> {
override fun process(file: VirtualFile): Boolean {
ProgressManager.checkCanceled()
if (findScriptDefinition(file, project) == null) return true
return scriptsCount++ < 3
}
}
val index = FileIndexFacade.getInstance(project)
return runReadAction {
FileBasedIndex.getInstance().processFilesContainingAllKeys(
IdIndex.NAME,
listOf(IdIndexEntry(name, true)),
scope,
null,
{ file -> !index.shouldBeFound(scope, file) || processor.process(file) })
}
}
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiSearchHelper.SearchCostResult
import com.intellij.psi.search.PsiSearchHelper.SearchCostResult.*
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.DefinitionsScopedSearch
@@ -109,7 +110,34 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
}
else -> return false
}
return lightElement != null && javaInspection.isEntryPoint(lightElement)
if (lightElement == null) return false
if (isCheapEnoughToSearchUsages(declaration) == TOO_MANY_OCCURRENCES) return false
return javaInspection.isEntryPoint(lightElement)
}
private fun isCheapEnoughToSearchUsages(declaration: KtNamedDeclaration): SearchCostResult {
val project = declaration.project
val psiSearchHelper = psiSearchHelperInstance(project)
val useScope = psiSearchHelper.getUseScope(declaration)
if (useScope is GlobalSearchScope) {
var zeroOccurrences = true
for (name in listOf(declaration.name) + declaration.getAccessorNames() + listOfNotNull(declaration.getClassNameForCompanionObject())) {
if (name == null) continue
when (psiSearchHelper.isCheapEnoughToSearchConsideringOperators(name, useScope, null, null)) {
ZERO_OCCURRENCES -> {
} // go on, check other names
FEW_OCCURRENCES -> zeroOccurrences = false
TOO_MANY_OCCURRENCES -> return TOO_MANY_OCCURRENCES // searching usages is too expensive; behave like it is used
}
}
if (zeroOccurrences) return ZERO_OCCURRENCES
}
return FEW_OCCURRENCES
}
private fun KtProperty.isSerializationImplicitlyUsedField(): Boolean {
@@ -223,18 +251,13 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
val project = declaration.project
val psiSearchHelper = psiSearchHelperInstance(project)
val useScope = declaration.useScope
val useScope = psiSearchHelper.getUseScope(declaration)
val restrictedScope = if (useScope is GlobalSearchScope) {
var zeroOccurrences = true
for (name in listOf(declaration.name) + declaration.getAccessorNames() + listOfNotNull(declaration.getClassNameForCompanionObject())) {
if (name == null) continue
when (psiSearchHelper.isCheapEnoughToSearchConsideringOperators(name, useScope, null, null)) {
ZERO_OCCURRENCES -> {
} // go on, check other names
FEW_OCCURRENCES -> zeroOccurrences = false
TOO_MANY_OCCURRENCES -> return true // searching usages is too expensive; behave like it is used
}
val enoughToSearchUsages = isCheapEnoughToSearchUsages(declaration)
val zeroOccurrences = when (enoughToSearchUsages) {
ZERO_OCCURRENCES -> true
FEW_OCCURRENCES -> false
TOO_MANY_OCCURRENCES -> return true // searching usages is too expensive; behave like it is used
}
if (zeroOccurrences && !declaration.hasActualModifier()) {