|
| 1 | +package org.tonstudio.tact.ide.highlight |
| 2 | + |
| 3 | +import com.intellij.codeInsight.daemon.LineMarkerInfo |
| 4 | +import com.intellij.codeInsight.daemon.LineMarkerProvider |
| 5 | +import com.intellij.icons.AllIcons |
| 6 | +import com.intellij.openapi.editor.markup.GutterIconRenderer |
| 7 | +import com.intellij.psi.PsiDocumentManager |
| 8 | +import com.intellij.psi.PsiElement |
| 9 | +import com.intellij.psi.util.parentOfType |
| 10 | +import com.intellij.util.FunctionUtil |
| 11 | +import org.tonstudio.tact.lang.psi.TactCallExpr |
| 12 | +import org.tonstudio.tact.lang.psi.TactFunctionOrMethodDeclaration |
| 13 | +import org.tonstudio.tact.lang.psi.TactReferenceExpression |
| 14 | + |
| 15 | +class TactRecursiveCallMarkerProvider : LineMarkerProvider { |
| 16 | + override fun getLineMarkerInfo(element: PsiElement) = null |
| 17 | + |
| 18 | + override fun collectSlowLineMarkers(elements: List<PsiElement>, result: MutableCollection<in LineMarkerInfo<*>?>) { |
| 19 | + val lines = mutableSetOf<Int>() |
| 20 | + for (element in elements) { |
| 21 | + if (element !is TactCallExpr) continue |
| 22 | + |
| 23 | + val resolve = (element.expression as? TactReferenceExpression)?.resolve() as? TactFunctionOrMethodDeclaration ?: continue |
| 24 | + |
| 25 | + if (isRecursiveCall(element, resolve)) { |
| 26 | + val document = PsiDocumentManager.getInstance(element.project).getDocument(element.containingFile) ?: continue |
| 27 | + val lineNumber = document.getLineNumber(element.textOffset) |
| 28 | + if (!lines.contains(lineNumber)) { |
| 29 | + result.add(RecursiveMethodCallMarkerInfo(element.identifier ?: element)) |
| 30 | + } |
| 31 | + |
| 32 | + lines.add(lineNumber) |
| 33 | + } |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + private class RecursiveMethodCallMarkerInfo(methodCall: PsiElement) : LineMarkerInfo<PsiElement?>( |
| 38 | + methodCall, |
| 39 | + methodCall.textRange, |
| 40 | + AllIcons.Gutter.RecursiveMethod, |
| 41 | + FunctionUtil.constant("Recursive call"), |
| 42 | + null, |
| 43 | + GutterIconRenderer.Alignment.RIGHT, |
| 44 | + { "Recursive call" } |
| 45 | + ) |
| 46 | + |
| 47 | + private fun isRecursiveCall(element: PsiElement, function: TactFunctionOrMethodDeclaration): Boolean { |
| 48 | + return element.parentOfType<TactFunctionOrMethodDeclaration>() == function |
| 49 | + } |
| 50 | +} |
0 commit comments