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.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.util.getThisReceiverOwner
|
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.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
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.ReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
|
|
||||||
public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
||||||
@@ -42,6 +43,7 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
|||||||
|
|
||||||
override fun collectSlowLineMarkers(elements: MutableList<PsiElement>, result: MutableCollection<LineMarkerInfo<*>>) {
|
override fun collectSlowLineMarkers(elements: MutableList<PsiElement>, result: MutableCollection<LineMarkerInfo<*>>) {
|
||||||
val markedLineNumbers = HashSet<Int>()
|
val markedLineNumbers = HashSet<Int>()
|
||||||
|
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
ProgressManager.checkCanceled()
|
ProgressManager.checkCanceled()
|
||||||
if (element is JetElement) {
|
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) {
|
for (parent in element.parents) {
|
||||||
when (parent) {
|
when (parent) {
|
||||||
is JetFunctionLiteral -> if (!InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return null
|
is JetFunctionLiteral -> if (stopOnNonInlinedLambdas && !InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return null
|
||||||
is JetNamedFunction -> if (!InlineUtil.isInlinedArgument(parent, parent.analyze(), false)) return parent
|
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
|
is JetClassOrObject -> return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,8 +73,14 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isRecursiveCall(element: JetElement): Boolean {
|
private fun isRecursiveCall(element: JetElement): Boolean {
|
||||||
if (element.getParent() is JetCallableReferenceExpression) return false
|
// Fast check for names without resolve
|
||||||
val enclosingFunction = getEnclosingFunction(element) ?: return false
|
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 bindingContext = element.analyze()
|
||||||
val enclosingFunctionDescriptor = bindingContext[BindingContext.FUNCTION, enclosingFunction] ?: return false
|
val enclosingFunctionDescriptor = bindingContext[BindingContext.FUNCTION, enclosingFunction] ?: return false
|
||||||
@@ -117,3 +130,34 @@ public class KotlinRecursiveCallLineMarkerProvider() : LineMarkerProvider {
|
|||||||
private fun PsiElement.getLineNumber(): Int {
|
private fun PsiElement.getLineNumber(): Int {
|
||||||
return PsiDocumentManager.getInstance(getProject()).getDocument(getContainingFile())!!.getLineNumber(getTextOffset())
|
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) {
|
fun Any.get(a: Int) {
|
||||||
if (a > 0) {
|
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