Do not run search for operator-like names in inspections

It might be rather expensive to search componentN's usages in the whole project
This commit is contained in:
Denis Zharkov
2017-11-16 20:10:15 +03:00
parent 0fbbe10143
commit 91730e1a9e
4 changed files with 27 additions and 9 deletions
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.search
import com.intellij.openapi.fileTypes.FileType import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.FileTypeRegistry import com.intellij.openapi.fileTypes.FileTypeRegistry
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
@@ -27,7 +28,9 @@ import com.intellij.psi.search.PsiSearchHelper
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.types.expressions.OperatorConventions
infix fun SearchScope.and(otherScope: SearchScope): SearchScope = intersectWith(otherScope) infix fun SearchScope.and(otherScope: SearchScope): SearchScope = intersectWith(otherScope)
infix fun SearchScope.or(otherScope: SearchScope): SearchScope = union(otherScope) infix fun SearchScope.or(otherScope: SearchScope): SearchScope = union(otherScope)
@@ -97,3 +100,14 @@ fun ReferencesSearch.SearchParameters.effectiveSearchScope(element: PsiElement):
fun isOnlyKotlinSearch(searchScope: SearchScope): Boolean { fun isOnlyKotlinSearch(searchScope: SearchScope): Boolean {
return searchScope is LocalSearchScope && searchScope.scope.all { it.containingFile is KtFile } return searchScope is LocalSearchScope && searchScope.scope.all { it.containingFile is KtFile }
} }
fun PsiSearchHelper.isCheapEnoughToSearchConsideringOperators(
name: String,
scope: GlobalSearchScope,
fileToIgnoreOccurrencesIn: PsiFile?,
progress: ProgressIndicator?
): PsiSearchHelper.SearchCostResult {
if (OperatorConventions.isConventionName(Name.identifier(name))) return PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES
return isCheapEnoughToSearch(name, scope, fileToIgnoreOccurrencesIn, progress)
}
@@ -33,6 +33,7 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.quickfix.RemoveValVarFromParameterFix import org.jetbrains.kotlin.idea.quickfix.RemoveValVarFromParameterFix
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.search.isCheapEnoughToSearchConsideringOperators
import org.jetbrains.kotlin.idea.search.usagesSearch.getAccessorNames import org.jetbrains.kotlin.idea.search.usagesSearch.getAccessorNames
import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -92,7 +93,7 @@ class CanBeParameterInspection : AbstractKotlinInspection() {
if (useScope is GlobalSearchScope) { if (useScope is GlobalSearchScope) {
val psiSearchHelper = PsiSearchHelper.SERVICE.getInstance(parameter.project) val psiSearchHelper = PsiSearchHelper.SERVICE.getInstance(parameter.project)
for (accessorName in parameter.getAccessorNames()) { for (accessorName in parameter.getAccessorNames()) {
when (psiSearchHelper.isCheapEnoughToSearch(accessorName, useScope, null, null)) { when (psiSearchHelper.isCheapEnoughToSearchConsideringOperators(accessorName, useScope, null, null)) {
ZERO_OCCURRENCES -> { ZERO_OCCURRENCES -> {
} // go on } // go on
else -> return // accessor in use: should remain a property else -> return // accessor in use: should remain a property
@@ -100,7 +101,7 @@ class CanBeParameterInspection : AbstractKotlinInspection() {
} }
// TOO_MANY_OCCURRENCES: too expensive // TOO_MANY_OCCURRENCES: too expensive
// ZERO_OCCURRENCES: unused at all, reported elsewhere // ZERO_OCCURRENCES: unused at all, reported elsewhere
if (psiSearchHelper.isCheapEnoughToSearch(name, useScope, null, null) != FEW_OCCURRENCES) return if (psiSearchHelper.isCheapEnoughToSearchConsideringOperators(name, useScope, null, null) != FEW_OCCURRENCES) return
} }
// Find all references and check them // Find all references and check them
val references = ReferencesSearch.search(parameter, useScope) val references = ReferencesSearch.search(parameter, useScope)
@@ -31,17 +31,19 @@ import com.intellij.util.Processor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.effectiveVisibility import org.jetbrains.kotlin.descriptors.effectiveVisibility
import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.core.isInheritable import org.jetbrains.kotlin.idea.core.isInheritable
import org.jetbrains.kotlin.idea.core.isOverridable import org.jetbrains.kotlin.idea.core.isOverridable
import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
import org.jetbrains.kotlin.idea.refactoring.isConstructorDeclaredProperty import org.jetbrains.kotlin.idea.refactoring.isConstructorDeclaredProperty
import org.jetbrains.kotlin.idea.search.isCheapEnoughToSearchConsideringOperators
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
class MemberVisibilityCanPrivateInspection : AbstractKotlinInspection() { class MemberVisibilityCanPrivateInspection : AbstractKotlinInspection() {
@@ -96,7 +98,7 @@ class MemberVisibilityCanPrivateInspection : AbstractKotlinInspection() {
val useScope = declaration.useScope val useScope = declaration.useScope
val name = declaration.name ?: return false val name = declaration.name ?: return false
if (useScope is GlobalSearchScope) { if (useScope is GlobalSearchScope) {
when (psiSearchHelper.isCheapEnoughToSearch(name, useScope, null, null)) { when (psiSearchHelper.isCheapEnoughToSearchConsideringOperators(name, useScope, null, null)) {
PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES -> return false PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES -> return false
PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES -> return false PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES -> return false
PsiSearchHelper.SearchCostResult.FEW_OCCURRENCES -> { PsiSearchHelper.SearchCostResult.FEW_OCCURRENCES -> {
@@ -61,6 +61,7 @@ import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.quickfix.RemoveUnusedFunctionParameterFix import org.jetbrains.kotlin.idea.quickfix.RemoveUnusedFunctionParameterFix
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.search.isCheapEnoughToSearchConsideringOperators
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.search.usagesSearch.getAccessorNames import org.jetbrains.kotlin.idea.search.usagesSearch.getAccessorNames
@@ -205,7 +206,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
for (name in listOf(declaration.name) + declaration.getAccessorNames() + listOfNotNull(declaration.getClassNameForCompanionObject())) { for (name in listOf(declaration.name) + declaration.getAccessorNames() + listOfNotNull(declaration.getClassNameForCompanionObject())) {
if (name == null) continue if (name == null) continue
when (psiSearchHelper.isCheapEnoughToSearch(name, useScope, null, null)) { when (psiSearchHelper.isCheapEnoughToSearchConsideringOperators(name, useScope, null, null)) {
ZERO_OCCURRENCES -> {} // go on, check other names ZERO_OCCURRENCES -> {} // go on, check other names
FEW_OCCURRENCES -> zeroOccurrences = false FEW_OCCURRENCES -> zeroOccurrences = false
TOO_MANY_OCCURRENCES -> return true // searching usages is too expensive; behave like it is used TOO_MANY_OCCURRENCES -> return true // searching usages is too expensive; behave like it is used