MethodReferencesSearch perfomance

I created simple LocalInspectionTool that checks is some specific extension function called on any of class object. This inspection registers problem on class declaration if that extension function not used with this class:

class MyInspection : AbstractKotlinInspection() {

override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : KtVisitorVoid() {

override fun visitClass(klass: KtClass) {
val classType = (klass.descriptor as? ClassDescriptor)?.defaultType ?: return
val extensionFunctionMethod = findExtensionFunctionMethod()
val isExtensionNotCalled = MethodReferencesSearch.search(testMethod).forEach(isCalleeTypeOf(classType))
if (isExtensionNotCalled) { //register problem }
}

}
}

fun isCalleeTypeOf(classType: KotlinType): Processor<PsiReference> = Processor {
val call = it.element.parent.parent
if (call is KtDotQualifiedExpression) {
val callExpression = call.firstChild as? KtExpression ?: return@Processor true
val callType = callExpression.getType(callExpression.analyze(BodyResolveMode.PARTIAL)) ?: return@Processor true
if (KotlinTypeChecker.DEFAULT.equalTypes(callType, classType)) {
return@Processor false
}
}
return@Processor true
}
}

This implementation takes very long time to analyze on a large project. Is MethodReferencesSearch.search runs method usages search on each class visit?

Is there any caches inside MethodReferencesSearch.search(method)?

How can I optimize this inspection, is there any way to perform more specific search (to find extension function calls only on expressions of specific type)?

1 comment

Yes, MethodReferencesSearch performs a search on every call. There is no caching (it would be quite hard to invalidate the cache correctly). There is no cache or index allowing to locate all expressions of a specific type in a project, so it would not be possible to look for calls on a receiver of a specific type efficiently.

The only way to optimize this inspection would be for you to build your own project service that caches the method references search result and keeps track of the receiver types for each call. This would still be not too efficient and hard to keep up-to-date when the code changes. I think it would be better to perform this kind of check as a global inspection running as part of Analyze | Inspect Code (when you can analyze the entire inspection scope in advance, and not individual files, and don't need to worry about code changes).

0

Please sign in to leave a comment.