Do psi-only checks to avoid unnessasary resolve in creating recursion markers
This commit is contained in:
+51
-7
@@ -28,13 +28,14 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.util.getThisReceiverOwner
|
||||
import org.jetbrains.kotlin.lexer.JetToken
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.HashSet
|
||||
|
||||
public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
||||
@@ -42,6 +43,7 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
||||
|
||||
override fun collectSlowLineMarkers(elements: MutableList<PsiElement>, result: MutableCollection<LineMarkerInfo<*>>) {
|
||||
val markedLineNumbers = HashSet<Int>()
|
||||
|
||||
for (element in elements) {
|
||||
ProgressManager.checkCanceled()
|
||||
if (element is JetElement) {
|
||||
@@ -54,11 +56,16 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getEnclosingFunction(element: JetElement): JetNamedFunction? {
|
||||
private fun getEnclosingFunction(element: JetElement, stopOnNonInlinedLambdas: Boolean): JetNamedFunction? {
|
||||
for (parent in element.parents) {
|
||||
when (parent) {
|
||||
is JetFunctionLiteral -> if (!InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return null
|
||||
is JetNamedFunction -> if (!InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return parent
|
||||
is JetFunctionLiteral -> if (stopOnNonInlinedLambdas && !InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return null
|
||||
is JetNamedFunction -> {
|
||||
when (parent.getParent()) {
|
||||
is JetBlockExpression, is JetClassBody, is JetFile, is JetScript -> return parent
|
||||
else -> if (stopOnNonInlinedLambdas && !InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return null
|
||||
}
|
||||
}
|
||||
is JetClassOrObject -> return null
|
||||
}
|
||||
}
|
||||
@@ -66,8 +73,14 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
||||
}
|
||||
|
||||
private fun isRecursiveCall(element: JetElement): Boolean {
|
||||
if (element.getParent() is JetCallableReferenceExpression) return false
|
||||
val enclosingFunction = getEnclosingFunction(element) ?: return false
|
||||
// Fast check for names without resolve
|
||||
val resolveName = getCallNameFromPsi(element) ?: return false
|
||||
val enclosingFunction = getEnclosingFunction(element, false) ?: return false
|
||||
|
||||
if (enclosingFunction.getName() != resolveName.asString()) return false
|
||||
|
||||
// Check that there were no not-inlined lambdas on the way to enclosing function
|
||||
if (enclosingFunction != getEnclosingFunction(element, true)) return false
|
||||
|
||||
val bindingContext = element.analyze()
|
||||
val enclosingFunctionDescriptor = bindingContext[BindingContext.FUNCTION, enclosingFunction] ?: return false
|
||||
@@ -117,3 +130,34 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
||||
private fun PsiElement.getLineNumber(): Int {
|
||||
return PsiDocumentManager.getInstance(getProject()).getDocument(getContainingFile())!!.getLineNumber(getTextOffset())
|
||||
}
|
||||
|
||||
private fun getCallNameFromPsi(element: JetElement): Name? {
|
||||
when (element) {
|
||||
is JetSimpleNameExpression -> {
|
||||
val elementParent = element.getParent()
|
||||
when (elementParent) {
|
||||
is JetCallExpression -> return Name.identifierNoValidate(element.getText())
|
||||
is JetOperationExpression -> {
|
||||
val operationReference = elementParent.getOperationReference()
|
||||
if (element == operationReference) {
|
||||
val node = operationReference.getReferencedNameElementType()
|
||||
return if (node is JetToken) {
|
||||
OperatorConventions.getNameForOperationSymbol(node) ?: Name.identifierNoValidate(element.getText())
|
||||
}
|
||||
else {
|
||||
Name.identifierNoValidate(element.getText())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is JetArrayAccessExpression ->
|
||||
return Name.identifier("get")
|
||||
is JetThisExpression ->
|
||||
if (element.getParent() is JetCallExpression) {
|
||||
return OperatorConventions.INVOKE
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1,5 +1,52 @@
|
||||
fun Any.get(a: Int) {
|
||||
if (a > 0) {
|
||||
<lineMarker>this[a - 1]</lineMarker>
|
||||
<lineMarker descr="Recursive call">this[a - 1]</lineMarker>
|
||||
}
|
||||
}
|
||||
|
||||
class A {
|
||||
override fun <lineMarker descr="Overrides function in 'Any'"></lineMarker>equals(other: Any?): Boolean {
|
||||
this <lineMarker descr="Recursive call">==</lineMarker> other
|
||||
return true
|
||||
}
|
||||
|
||||
fun inc(): A {
|
||||
this<lineMarker descr="Recursive call">++</lineMarker>
|
||||
<lineMarker descr="Recursive call">++</lineMarker>this
|
||||
return this
|
||||
}
|
||||
|
||||
fun component1(): Int {
|
||||
// TODO: should be recursion marker too
|
||||
val (a) = this
|
||||
return 1
|
||||
}
|
||||
|
||||
fun plus() {
|
||||
<lineMarker descr="Recursive call">+</lineMarker>this
|
||||
}
|
||||
|
||||
fun minus() {
|
||||
<lineMarker descr="Recursive call">-</lineMarker>this
|
||||
}
|
||||
|
||||
fun plus(a: Int) {
|
||||
this <lineMarker descr="Recursive call">+</lineMarker> 1
|
||||
this += 1
|
||||
}
|
||||
|
||||
fun invoke() {
|
||||
val a = A()
|
||||
a()
|
||||
a.invoke()
|
||||
|
||||
this.<lineMarker descr="Recursive call">invoke</lineMarker>()
|
||||
<lineMarker descr="Recursive call">this</lineMarker>()
|
||||
}
|
||||
}
|
||||
|
||||
class B
|
||||
fun B.invoke() {
|
||||
<lineMarker descr="Recursive call">this</lineMarker>()
|
||||
<lineMarker descr="Recursive call">invoke</lineMarker>()
|
||||
}
|
||||
Reference in New Issue
Block a user