From b17283bda431a5660cf6584e6b823e5c6f42ae5b Mon Sep 17 00:00:00 2001 From: Maksim Kurnikov Date: Sun, 16 Jun 2024 13:49:43 +0300 Subject: [PATCH] parameter info, inlay parameter hints for receiver style functions --- .../move/ide/annotator/MvErrorAnnotator.kt | 4 +-- .../annotator/fixes/ItemSpecSignatureFix.kt | 4 +-- .../ide/hints/FunctionParameterInfoHandler.kt | 16 +++++++---- .../org/move/ide/hints/InlayParameterHints.kt | 22 ++++++++------- .../org/move/ide/utils/FunctionSignature.kt | 27 +++++++++++-------- .../move/ide/hints/InlayParameterHintsTest.kt | 14 ++++++++++ .../ide/hints/ParameterInfoHandlerTest.kt | 13 +++++++++ 7 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt index 336d46805..769940a48 100644 --- a/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt +++ b/src/main/kotlin/org/move/ide/annotator/MvErrorAnnotator.kt @@ -5,7 +5,7 @@ import com.intellij.psi.PsiElement import org.move.ide.presentation.fullname import org.move.ide.presentation.itemDeclaredInModule import org.move.ide.utils.functionSignature -import org.move.ide.utils.signature +import org.move.ide.utils.getSignature import org.move.lang.MvElementTypes.R_PAREN import org.move.lang.core.psi.* import org.move.lang.core.psi.ext.* @@ -65,7 +65,7 @@ class MvErrorAnnotator: MvAnnotatorBase() { override fun visitItemSpec(itemSpec: MvItemSpec) { val funcItem = itemSpec.funcItem ?: return - val funcSignature = funcItem.signature ?: return + val funcSignature = funcItem.getSignature() ?: return val itemSpecSignature = itemSpec.itemSpecSignature ?: return val specSignature = itemSpecSignature.functionSignature diff --git a/src/main/kotlin/org/move/ide/annotator/fixes/ItemSpecSignatureFix.kt b/src/main/kotlin/org/move/ide/annotator/fixes/ItemSpecSignatureFix.kt index 23e521e11..c011df473 100644 --- a/src/main/kotlin/org/move/ide/annotator/fixes/ItemSpecSignatureFix.kt +++ b/src/main/kotlin/org/move/ide/annotator/fixes/ItemSpecSignatureFix.kt @@ -3,7 +3,7 @@ package org.move.ide.annotator.fixes import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import org.move.ide.inspections.DiagnosticIntentionFix -import org.move.ide.utils.signature +import org.move.ide.utils.getSignature import org.move.lang.core.psi.MvItemSpec import org.move.lang.core.psi.ext.funcItem import org.move.lang.core.psi.psiFactory @@ -17,7 +17,7 @@ class ItemSpecSignatureFix( override fun invoke(project: Project, file: PsiFile, element: MvItemSpec) { val itemSpec = startElement - val actualSignature = itemSpec.funcItem?.signature ?: return + val actualSignature = itemSpec.funcItem?.getSignature() ?: return val psiFactory = project.psiFactory val newSpecSignature = psiFactory.itemSpecSignature(actualSignature) diff --git a/src/main/kotlin/org/move/ide/hints/FunctionParameterInfoHandler.kt b/src/main/kotlin/org/move/ide/hints/FunctionParameterInfoHandler.kt index 988889f17..69be9a615 100644 --- a/src/main/kotlin/org/move/ide/hints/FunctionParameterInfoHandler.kt +++ b/src/main/kotlin/org/move/ide/hints/FunctionParameterInfoHandler.kt @@ -7,14 +7,15 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiFile import org.move.ide.utils.FunctionSignature import org.move.lang.MvElementTypes -import org.move.lang.core.psi.MvCallExpr +import org.move.lang.core.psi.MvMethodCall import org.move.lang.core.psi.MvStructLitFieldsBlock import org.move.lang.core.psi.MvValueArgumentList +import org.move.lang.core.psi.ext.MvCallable import org.move.lang.core.psi.ext.ancestorOrSelf import org.move.lang.core.psi.ext.startOffset import org.move.utils.AsyncParameterInfoHandlerBase -class FunctionParameterInfoHandler : AsyncParameterInfoHandlerBase() { +class FunctionParameterInfoHandler: AsyncParameterInfoHandlerBase() { override fun findTargetElement(file: PsiFile, offset: Int): MvValueArgumentList? { val element = file.findElementAt(offset) ?: return null @@ -80,9 +81,14 @@ class ParamsDescription(val parameters: Array) { * Finds declaration of the func/method and creates description of its arguments */ fun findDescription(args: MvValueArgumentList): ParamsDescription? { - val signature = - (args.parent as? MvCallExpr)?.let { FunctionSignature.resolve(it) } ?: return null - val params = signature.parameters.map { "${it.name}: ${it.type}" } + val callable = args.parent as? MvCallable ?: return null + val signature = FunctionSignature.resolve(callable) ?: return null + val params = + when (callable) { + is MvMethodCall -> signature.parameters.drop(1) + else -> signature.parameters + } + .map { "${it.name}: ${it.type}" } return ParamsDescription(params.toTypedArray()) } } diff --git a/src/main/kotlin/org/move/ide/hints/InlayParameterHints.kt b/src/main/kotlin/org/move/ide/hints/InlayParameterHints.kt index ab11dbc33..d13ac0ec5 100644 --- a/src/main/kotlin/org/move/ide/hints/InlayParameterHints.kt +++ b/src/main/kotlin/org/move/ide/hints/InlayParameterHints.kt @@ -3,25 +3,27 @@ package org.move.ide.hints import com.intellij.codeInsight.hints.InlayInfo import com.intellij.psi.PsiElement import org.move.ide.utils.FunctionSignature -import org.move.lang.core.psi.MvCallExpr -import org.move.lang.core.psi.MvRefExpr -import org.move.lang.core.psi.MvStructLitExpr +import org.move.lang.core.psi.* +import org.move.lang.core.psi.ext.MvCallable import org.move.lang.core.psi.ext.argumentExprs import org.move.lang.core.psi.ext.startOffset @Suppress("UnstableApiUsage") object InlayParameterHints { - fun provideHints(elem: PsiElement): List { - if (elem !is MvCallExpr) return emptyList() - - val signature = FunctionSignature.resolve(elem) ?: return emptyList() - return signature.parameters + fun provideHints(element: PsiElement): List { + if (element !is MvCallable) return emptyList() + val signature = FunctionSignature.resolve(element) ?: return emptyList() + val parameters = when (element) { + is MvMethodCall -> signature.parameters.drop(1) + else -> signature.parameters + } + return parameters .map { it.name } - .zip(elem.argumentExprs) + .zip(element.argumentExprs) .asSequence() .filter { (_, arg) -> arg != null } // don't show argument, if just function call / variable / struct literal - // .filter { (_, arg) -> arg !is MvRefExpr && arg !is MvCallExpr && arg !is MvStructLitExpr } + // .filter { (_, arg) -> arg !is MvRefExpr && arg !is MvCallExpr && arg !is MvStructLitExpr } .filter { (_, arg) -> arg !is MvRefExpr && arg !is MvStructLitExpr } .filter { (hint, arg) -> !isSimilar(hint, arg!!.text) } .filter { (hint, _) -> hint != "_" } diff --git a/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt b/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt index 043c57801..7b6796aeb 100644 --- a/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt +++ b/src/main/kotlin/org/move/ide/utils/FunctionSignature.kt @@ -9,10 +9,7 @@ import com.intellij.openapi.util.Key import com.intellij.psi.util.CachedValue import com.intellij.psi.util.CachedValueProvider import org.move.lang.core.psi.* -import org.move.lang.core.psi.ext.ability -import org.move.lang.core.psi.ext.abilityBounds -import org.move.lang.core.psi.ext.bounds -import org.move.lang.core.psi.ext.name +import org.move.lang.core.psi.ext.* import org.move.lang.core.types.ty.Ability import org.move.utils.cache import org.move.utils.cacheManager @@ -44,10 +41,18 @@ data class FunctionSignature( } companion object { - fun resolve(callExpr: MvCallExpr): FunctionSignature? { - val function = callExpr.path.reference?.resolveWithAliases() as? MvFunction - return function?.signature - } + fun resolve(callable: MvCallable): FunctionSignature? = + when (callable) { + is MvCallExpr -> { + val function = callable.path.reference?.resolveWithAliases() as? MvFunction + function?.getSignature() + } + is MvMethodCall -> { + val function = callable.reference.resolveWithAliases() as? MvFunction + function?.getSignature() + } + else -> null + } fun fromFunction(function: MvFunction): FunctionSignature? { val typeParameters = function.typeParameters @@ -87,10 +92,10 @@ data class FunctionSignature( } } -private val SIGNATURE_KEY: Key> = Key.create("SIGNATURE_KEY") +private val FUNCTION_SIGNATURE_KEY: Key> = Key.create("SIGNATURE_KEY") -val MvFunction.signature: FunctionSignature? - get() = project.cacheManager.cache(this, SIGNATURE_KEY) { +fun MvFunction.getSignature(): FunctionSignature? = + project.cacheManager.cache(this, FUNCTION_SIGNATURE_KEY) { val signature = FunctionSignature.fromFunction(this) CachedValueProvider.Result.create( signature, diff --git a/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt b/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt index 9325686cb..4e14ccf77 100644 --- a/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt +++ b/src/test/kotlin/org/move/ide/hints/InlayParameterHintsTest.kt @@ -2,6 +2,7 @@ package org.move.ide.hints import com.intellij.codeInsight.daemon.impl.HintRenderer import org.intellij.lang.annotations.Language +import org.move.utils.tests.CompilerV2 import org.move.utils.tests.MvTestBase class InlayParameterHintsTest : MvTestBase() { @@ -61,6 +62,19 @@ class InlayParameterHintsTest : MvTestBase() { """ ) + @CompilerV2 + fun `test receiver style fun`() = checkByText( + """ + module 0x1::m { + struct S { val: u8 } + fun get_val(self: &S, modifier: bool): u8 { self.val } + fun main(s: S) { + s.get_val(/*hint text="modifier:"*/true); + } + } + """ + ) + private fun checkByText(@Language("Move") code: String) { InlineFile( code.trimIndent() diff --git a/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt b/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt index 856bd966f..658466ead 100644 --- a/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt +++ b/src/test/kotlin/org/move/ide/hints/ParameterInfoHandlerTest.kt @@ -1,6 +1,7 @@ package org.move.ide.hints import org.move.lang.core.psi.MvValueArgumentList +import org.move.utils.tests.CompilerV2 import org.move.utils.tests.ParameterInfoHandlerTestCase class ParameterInfoHandlerTest @@ -124,4 +125,16 @@ class ParameterInfoHandlerTest fun main() { call(42, 10, /*caret*/); } } """, "val1: u8, val2: u8, val3: u8", 2) + + @CompilerV2 + fun `test receiver style fun`() = checkByText( + """ + module 0x1::m { + struct S { val: u8 } + fun get_val(self: &S, modifier: bool): u8 { self.val } + fun main(s: S) { + s.get_val(/*caret*/); + } + } + """, "modifier: bool", 0) }