Optimization

This commit is contained in:
Valentin Kipyatkov
2016-09-24 18:11:22 +03:00
parent 4cc16e42b2
commit 309d82308f
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.search.excludeFileTypes import org.jetbrains.kotlin.idea.search.excludeFileTypes
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
@@ -204,7 +205,7 @@ class ExpressionsOfTypeProcessor(
addTask(ProcessClassUsagesTask(classToSearch)) addTask(ProcessClassUsagesTask(classToSearch))
} }
private fun addCallableDeclarationToProcess(declaration: PsiElement, processMethod: (PsiReference) -> Boolean) { private fun addCallableDeclarationToProcess(declaration: PsiElement, scope: SearchScope, processMethod: (PsiReference) -> Boolean) {
if (declaration.isOperatorExpensiveToSearch()) { // cancel all tasks and use plain search if (declaration.isOperatorExpensiveToSearch()) { // cancel all tasks and use plain search
downShiftToPlainSearch() downShiftToPlainSearch()
return return
@@ -212,8 +213,6 @@ class ExpressionsOfTypeProcessor(
data class ProcessCallableUsagesTask(val declaration: PsiElement, val processMethod: (PsiReference) -> Boolean) : Task { data class ProcessCallableUsagesTask(val declaration: PsiElement, val processMethod: (PsiReference) -> Boolean) : Task {
override fun perform() { override fun perform() {
// we don't need to search usages of declarations in Java because Java doesn't have implicitly typed declarations so such usages cannot affect Kotlin code
val scope = GlobalSearchScope.projectScope(project).excludeFileTypes(JavaFileType.INSTANCE, XmlFileType.INSTANCE)
testLog?.add("Searched references to ${logPresentation(declaration)} in non-Java files") testLog?.add("Searched references to ${logPresentation(declaration)} in non-Java files")
val searchParameters = KotlinReferencesSearchParameters( val searchParameters = KotlinReferencesSearchParameters(
declaration, scope, kotlinOptions = KotlinReferencesSearchOptions(searchNamedArguments = false)) declaration, scope, kotlinOptions = KotlinReferencesSearchOptions(searchNamedArguments = false))
@@ -229,8 +228,21 @@ class ExpressionsOfTypeProcessor(
addTask(ProcessCallableUsagesTask(declaration, processMethod)) addTask(ProcessCallableUsagesTask(declaration, processMethod))
} }
private val HAS_OUR_TYPE = this::processReferenceToCallableOfOurType private fun addCallableDeclarationOfOurType(declaration: PsiElement) {
private val PROCESS_LAMBDAS = this::processLambdasByCallableReference addCallableDeclarationToProcess(declaration, searchScope.restrictToKotlinSources(), this::processReferenceToCallableOfOurType)
}
/**
* Process references to declaration which has parameter of functional type with our class used inside
*/
private fun addCallableDeclarationToProcessLambdasInCalls(declaration: PsiElement) {
// we don't need to search usages of declarations in Java because Java doesn't have implicitly typed declarations so such usages cannot affect Kotlin code
val scope = GlobalSearchScope.projectScope(project).excludeFileTypes(JavaFileType.INSTANCE, XmlFileType.INSTANCE)
addCallableDeclarationToProcess(declaration, scope) { reference ->
(reference.element as? KtReferenceExpression)?.let { processLambdasForCallableReference(it) }
true
}
}
/** /**
* Process reference to declaration whose type is our class (or our class used anywhere inside that type) * Process reference to declaration whose type is our class (or our class used anywhere inside that type)
@@ -240,7 +252,7 @@ class ExpressionsOfTypeProcessor(
KotlinLanguage.INSTANCE -> { KotlinLanguage.INSTANCE -> {
if (reference is KtDestructuringDeclarationReference) { if (reference is KtDestructuringDeclarationReference) {
// declaration usage in form of destructuring declaration entry // declaration usage in form of destructuring declaration entry
addCallableDeclarationToProcess(reference.element, HAS_OUR_TYPE) addCallableDeclarationOfOurType(reference.element)
} }
else { else {
(reference.element as? KtReferenceExpression)?.let { processSuspiciousExpression(it) } (reference.element as? KtReferenceExpression)?.let { processSuspiciousExpression(it) }
@@ -252,14 +264,6 @@ class ExpressionsOfTypeProcessor(
} }
} }
/**
* Process reference to declaration which has parameter of functional type with our class used inside
*/
private fun processLambdasByCallableReference(reference: PsiReference): Boolean {
(reference.element as? KtReferenceExpression)?.let { processLambdasForCallableReference(it) }
return true
}
private fun addSamInterfaceToProcess(psiClass: PsiClass) { private fun addSamInterfaceToProcess(psiClass: PsiClass) {
data class ProcessSamInterfaceTask(val psiClass: PsiClass) : Task { data class ProcessSamInterfaceTask(val psiClass: PsiClass) : Task {
override fun perform() { override fun perform() {
@@ -275,7 +279,7 @@ class ExpressionsOfTypeProcessor(
val parameter = ((reference as? PsiJavaCodeReferenceElement)?.parent as? PsiTypeElement)?.parent as? PsiParameter val parameter = ((reference as? PsiJavaCodeReferenceElement)?.parent as? PsiTypeElement)?.parent as? PsiParameter
val method = parameter?.declarationScope as? PsiMethod val method = parameter?.declarationScope as? PsiMethod
if (method != null) { if (method != null) {
addCallableDeclarationToProcess(method, PROCESS_LAMBDAS) addCallableDeclarationToProcessLambdasInCalls(method)
} }
true true
} }
@@ -372,14 +376,14 @@ class ExpressionsOfTypeProcessor(
is KtCallableDeclaration -> { is KtCallableDeclaration -> {
when (typeRef) { when (typeRef) {
typeRefParent.typeReference -> { // usage in type of callable declaration typeRefParent.typeReference -> { // usage in type of callable declaration
addCallableDeclarationToProcess(typeRefParent, HAS_OUR_TYPE) addCallableDeclarationOfOurType(typeRefParent)
if (typeRefParent is KtParameter) { //TODO: what if functional type is declared with "FunctionN<...>"? if (typeRefParent is KtParameter) { //TODO: what if functional type is declared with "FunctionN<...>"?
val usedInsideFunctionalType = userType.parents.takeWhile { it != typeRef }.any { it is KtFunctionType } val usedInsideFunctionalType = userType.parents.takeWhile { it != typeRef }.any { it is KtFunctionType }
if (usedInsideFunctionalType) { if (usedInsideFunctionalType) {
val function = (typeRefParent.parent as? KtParameterList)?.parent as? KtFunction val function = (typeRefParent.parent as? KtParameterList)?.parent as? KtFunction
if (function != null) { if (function != null) {
addCallableDeclarationToProcess(function, PROCESS_LAMBDAS) addCallableDeclarationOfOurType(function)
} }
} }
} }
@@ -463,14 +467,14 @@ class ExpressionsOfTypeProcessor(
is PsiMethod -> { is PsiMethod -> {
if (prev == parent.returnTypeElement && !parent.isPrivateOrLocal()) { // usage in return type of a method if (prev == parent.returnTypeElement && !parent.isPrivateOrLocal()) { // usage in return type of a method
addCallableDeclarationToProcess(parent, HAS_OUR_TYPE) addCallableDeclarationOfOurType(parent)
} }
break@ParentsLoop break@ParentsLoop
} }
is PsiField -> { is PsiField -> {
if (prev == parent.typeElement && !parent.isPrivateOrLocal()) { // usage in type of a field if (prev == parent.typeElement && !parent.isPrivateOrLocal()) { // usage in type of a field
addCallableDeclarationToProcess(parent, HAS_OUR_TYPE) addCallableDeclarationOfOurType(parent)
} }
break@ParentsLoop break@ParentsLoop
} }
@@ -582,7 +586,7 @@ class ExpressionsOfTypeProcessor(
val descriptor = declaration.resolveToDescriptorIfAny() as? CallableDescriptor ?: return val descriptor = declaration.resolveToDescriptorIfAny() as? CallableDescriptor ?: return
val type = descriptor.returnType val type = descriptor.returnType
if (type != null && type.containsTypeOrDerivedInside(typeToSearch)) { if (type != null && type.containsTypeOrDerivedInside(typeToSearch)) {
addCallableDeclarationToProcess(declaration, HAS_OUR_TYPE) addCallableDeclarationOfOurType(declaration)
} }
} }
} }