Skip to content

Commit f068d1f

Browse files
authored
Merge pull request #219 from pontem-network/method-parameter-info
Refactor parameter info, infer types in methods for parameter info
2 parents e4ff57e + 1a02619 commit f068d1f

12 files changed

+413
-80
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.move.ide.hints
2+
3+
import org.move.ide.presentation.tyToString
4+
import org.move.lang.core.psi.*
5+
import org.move.lang.core.psi.ext.isMsl
6+
import org.move.lang.core.psi.ext.name
7+
import org.move.lang.core.types.infer.inference
8+
import org.move.lang.core.types.ty.*
9+
10+
class CallInfo(
11+
val selfParameter: String?,
12+
val parameters: List<Parameter>
13+
) {
14+
class Parameter(val name: String?, val type: MvType?, val ty: Ty? = null) {
15+
fun renderType(): String {
16+
return if (ty != null && ty !is TyUnknown) {
17+
tyToString(ty)
18+
} else {
19+
type?.text ?: "_"
20+
}
21+
}
22+
}
23+
24+
companion object {
25+
fun resolve(callExpr: MvCallExpr): CallInfo? {
26+
val fn = callExpr.path.reference?.resolveFollowingAliases() as? MvFunction ?: return null
27+
val msl = callExpr.isMsl()
28+
val callTy = callExpr.inference(msl)?.getCallableType(callExpr) as? TyFunction ?: return null
29+
return buildFunctionParameters(fn, callTy)
30+
}
31+
32+
fun resolve(assertMacroExpr: MvAssertMacroExpr): CallInfo {
33+
return CallInfo(null, buildList {
34+
add(Parameter("_", null, TyBool))
35+
add(Parameter("err", null, TyInteger(TyInteger.Kind.u64)))
36+
})
37+
}
38+
39+
fun resolve(methodCall: MvMethodCall): CallInfo? {
40+
val fn = methodCall.reference.resolveFollowingAliases() as? MvFunction ?: return null
41+
val msl = methodCall.isMsl()
42+
val callTy = methodCall.inference(msl)?.getCallableType(methodCall) as? TyFunction ?: return null
43+
return buildFunctionParameters(fn, callTy)
44+
}
45+
46+
private fun buildFunctionParameters(function: MvFunction, ty: TyFunction): CallInfo {
47+
val tys = ty.paramTypes.drop(if (function.isMethod) 1 else 0)
48+
val params = function.parameters
49+
.drop(if (function.isMethod) 1 else 0).map { it.name to it.type }
50+
val self = function.selfParam?.let {
51+
ty.paramTypes.firstOrNull()?.let { "self: ${tyToString(it)}" } ?: "_"
52+
}
53+
return CallInfo(self, buildParameters(tys, params))
54+
}
55+
56+
private fun buildParameters(
57+
argumentTys: List<Ty>,
58+
parameterTypes: List<Pair<String?, MvType?>>,
59+
): List<Parameter> {
60+
return argumentTys.zip(parameterTypes).map { (ty, param) ->
61+
val (name, parameterType) = param
62+
Parameter(name, parameterType, ty)
63+
}
64+
}
65+
}
66+
67+
// private constructor(fn: MvFunction, parameters: List<Parameter>): this(
68+
// fn.selfParam?.let { self ->
69+
// buildString {
70+
//// if (self.isRef) append("&")
71+
//// if (self.mutability.isMut) append("mut ")
72+
// append("self: ${fn.selfParamTy()}")
73+
// }
74+
// },
75+
// parameters
76+
// )
77+
78+
// private constructor(parameters: List<Parameter>) : this(
79+
// null,
80+
// parameters
81+
// )
82+
}

src/main/kotlin/org/move/ide/hints/TypeParameterInfoHandler.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ class TypeParamsDescription(
7676
* Calculates the text representation and ranges for parameters
7777
*/
7878
private fun typeParamsDescription(params: List<MvTypeParameter>): TypeParamsDescription {
79-
val parts = params.map {
79+
val arguments = params.map {
8080
val name = it.name ?: "_"
8181
val bound = it.typeParamBound?.text ?: ""
8282
name + bound
8383
}
84-
val presentText = if (parts.isEmpty()) "<no arguments>" else parts.joinToString(", ")
84+
val presentText = if (arguments.isEmpty()) "<no arguments>" else arguments.joinToString(", ")
8585
return TypeParamsDescription(
8686
presentText,
87-
parts.indices.map { parts.calculateRange(it) }
87+
arguments.indices.map { arguments.calculateRange(it) }
8888
)
8989
}
9090

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.move.ide.hints.paramInfo
2+
3+
import com.intellij.lang.parameterInfo.*
4+
import com.intellij.psi.PsiElement
5+
import org.move.lang.MvElementTypes
6+
import org.move.lang.core.psi.ext.ancestors
7+
import org.move.lang.core.psi.ext.elementType
8+
import org.move.lang.core.psi.ext.startOffset
9+
10+
class CompositeParameterInfoHandler: ParameterInfoHandler<PsiElement, ParameterInfoProvider.ParametersInfo> {
11+
12+
val providers: List<ParameterInfoProvider> =
13+
buildList {
14+
add(FunctionParameterInfoProvider())
15+
add(TypeParameterInfoProvider())
16+
}
17+
18+
// should store the information about arguments into the `itemsToShow` variable to use later
19+
override fun findElementForParameterInfo(context: CreateParameterInfoContext): PsiElement? {
20+
val (listElement, provider) = findTargetElement(context) ?: return null
21+
context.itemsToShow =
22+
provider.findParameterInfo(listElement)?.let { arrayOf(it) } ?: return null
23+
return listElement
24+
}
25+
26+
override fun findElementForUpdatingParameterInfo(context: UpdateParameterInfoContext): PsiElement? {
27+
val (listElement, _) = findTargetElement(context) ?: return null
28+
return listElement
29+
}
30+
31+
override fun showParameterInfo(element: PsiElement, context: CreateParameterInfoContext) {
32+
context.showHint(element, element.startOffset, this)
33+
}
34+
35+
override fun updateParameterInfo(listElement: PsiElement, context: UpdateParameterInfoContext) {
36+
if (context.parameterOwner != listElement) {
37+
context.removeHint()
38+
return
39+
}
40+
val contextOffset = context.offset
41+
val currentParameterIndex =
42+
if (listElement.startOffset == contextOffset) {
43+
-1
44+
} else {
45+
ParameterInfoUtils.getCurrentParameterIndex(
46+
listElement.node,
47+
context.offset,
48+
MvElementTypes.COMMA
49+
)
50+
// if (listElement.valueArgumentList.isEmpty()) {
51+
// 0
52+
// } else {
53+
// }
54+
}
55+
context.setCurrentParameter(currentParameterIndex)
56+
}
57+
58+
override fun updateUI(paramsInfo: ParameterInfoProvider.ParametersInfo, context: ParameterInfoUIContext) {
59+
val argumentRange = paramsInfo.getRangeInParent(context.currentParameterIndex)
60+
context.setupUIComponentPresentation(
61+
paramsInfo.presentText,
62+
argumentRange.startOffset,
63+
argumentRange.endOffset,
64+
!context.isUIComponentEnabled,
65+
false,
66+
false,
67+
context.defaultParameterColor
68+
)
69+
}
70+
71+
private fun findTargetElement(context: ParameterInfoContext): Pair<PsiElement, ParameterInfoProvider>? {
72+
val element = context.file.findElementAt(context.offset) ?: return null
73+
return run {
74+
for (ancestor in element.ancestors) {
75+
for (provider in providers) {
76+
if (provider.targetElementType == ancestor.elementType) {
77+
return@run ancestor to provider
78+
}
79+
}
80+
}
81+
null
82+
}
83+
}
84+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.move.ide.hints.paramInfo
2+
3+
import com.intellij.openapi.util.TextRange
4+
import com.intellij.psi.PsiElement
5+
import com.intellij.psi.tree.IElementType
6+
import org.move.ide.hints.CallInfo
7+
import org.move.ide.hints.paramInfo.ParameterInfoProvider.ParametersInfo
8+
import org.move.lang.MvElementTypes.VALUE_ARGUMENT_LIST
9+
import org.move.lang.core.psi.MvAssertMacroExpr
10+
import org.move.lang.core.psi.MvCallExpr
11+
import org.move.lang.core.psi.MvMethodCall
12+
import org.move.lang.core.psi.MvValueArgumentList
13+
import org.move.lang.core.psi.ext.MvCallable
14+
15+
class FunctionParameterInfoProvider: ParameterInfoProvider {
16+
override val targetElementType: IElementType get() = VALUE_ARGUMENT_LIST
17+
18+
class FunctionParametersInfo(val parameters: List<String>): ParametersInfo {
19+
override val presentText: String
20+
get() = if (parameters.isEmpty()) "<no arguments>" else parameters.joinToString(", ")
21+
22+
override fun getRangeInParent(index: Int): TextRange {
23+
if (index < 0 || index >= parameters.size) return TextRange.EMPTY_RANGE
24+
val start = parameters.take(index).sumOf { it.length + 2 }
25+
return TextRange(start, start + parameters[index].length)
26+
}
27+
}
28+
29+
override fun findParameterInfo(listElement: PsiElement): FunctionParametersInfo? {
30+
val argumentList = listElement as MvValueArgumentList
31+
val call = argumentList.parent as? MvCallable ?: return null
32+
val callInfo = when (call) {
33+
is MvCallExpr -> CallInfo.resolve(call)
34+
is MvMethodCall -> CallInfo.resolve(call)
35+
is MvAssertMacroExpr -> CallInfo.resolve(call)
36+
else -> null
37+
} ?: return null
38+
val parameters = buildList {
39+
// self parameter with non-dot-expr call
40+
if (callInfo.selfParameter != null && call is MvCallExpr) {
41+
add(callInfo.selfParameter)
42+
}
43+
addAll(callInfo.parameters.map {
44+
buildString {
45+
if (it.name != null) {
46+
append("${it.name}: ")
47+
}
48+
append(it.renderType())
49+
}
50+
})
51+
}
52+
return FunctionParametersInfo(parameters)
53+
}
54+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.move.ide.hints.paramInfo
2+
3+
import com.intellij.openapi.util.TextRange
4+
import com.intellij.psi.PsiElement
5+
import com.intellij.psi.tree.IElementType
6+
7+
interface ParameterInfoProvider {
8+
val targetElementType: IElementType
9+
fun findParameterInfo(listElement: PsiElement): ParametersInfo?
10+
11+
interface ParametersInfo {
12+
val presentText: String
13+
fun getRangeInParent(index: Int): TextRange
14+
}
15+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.move.ide.hints.paramInfo
2+
3+
import com.intellij.openapi.util.TextRange
4+
import com.intellij.psi.PsiElement
5+
import com.intellij.psi.tree.IElementType
6+
import org.move.ide.hints.paramInfo.ParameterInfoProvider.ParametersInfo
7+
import org.move.lang.MvElementTypes.TYPE_ARGUMENT_LIST
8+
import org.move.lang.core.psi.*
9+
10+
class TypeParameterInfoProvider: ParameterInfoProvider {
11+
override val targetElementType: IElementType get() = TYPE_ARGUMENT_LIST
12+
13+
override fun findParameterInfo(listElement: PsiElement): ParametersInfo? {
14+
val parentPath = listElement.parent as? MvPath ?: return null
15+
val owner = parentPath.reference?.resolveFollowingAliases() ?: return null
16+
// if zero type parameters
17+
if (owner !is MvGenericDeclaration) return null
18+
val typeParameters =
19+
owner.typeParameters.map { (it.name ?: "_") + (it.typeParamBound?.text ?: "") }
20+
val textRanges = typeParameters.indices.map { typeParameters.calculateRange(it) }
21+
return TypeParametersInfo(typeParameters, textRanges)
22+
23+
}
24+
25+
class TypeParametersInfo(
26+
val typeParameters: List<String>,
27+
val ranges: List<TextRange>
28+
): ParametersInfo {
29+
override val presentText: String
30+
get() = if (typeParameters.isEmpty()) "<no arguments>" else typeParameters.joinToString(", ")
31+
32+
override fun getRangeInParent(index: Int): TextRange {
33+
return if (index !in ranges.indices) TextRange.EMPTY_RANGE else ranges[index]
34+
}
35+
}
36+
}
37+
38+
private fun List<String>.calculateRange(index: Int): TextRange {
39+
val start = this.take(index).sumOf { it.length + 2 } // plus ", "
40+
return TextRange(start, start + this[index].length)
41+
}
42+

src/main/kotlin/org/move/ide/liveTemplates/MvContextType.kt

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.move.ide.liveTemplates
22

3-
import com.intellij.codeInsight.template.EverywhereContextType
43
import com.intellij.codeInsight.template.TemplateActionContext
54
import com.intellij.codeInsight.template.TemplateContextType
65
import com.intellij.openapi.fileTypes.SyntaxHighlighter
@@ -13,13 +12,8 @@ import org.move.ide.MvHighlighter
1312
import org.move.lang.MoveLanguage
1413
import org.move.lang.core.psi.MvCodeBlock
1514
import org.move.lang.core.psi.MvModule
16-
import kotlin.reflect.KClass
1715

18-
sealed class MvContextType(
19-
id: String,
20-
presentableName: String,
21-
baseContextType: KClass<out TemplateContextType>
22-
) : TemplateContextType(id, presentableName, baseContextType.java) {
16+
sealed class MvContextType(presentableName: String): TemplateContextType(presentableName) {
2317

2418
final override fun isInContext(context: TemplateActionContext): Boolean {
2519
if (!PsiUtilCore.getLanguageAtOffset(context.file, context.startOffset).isKindOf(MoveLanguage)) {
@@ -38,20 +32,16 @@ sealed class MvContextType(
3832

3933
override fun createHighlighter(): SyntaxHighlighter = MvHighlighter()
4034

41-
class Generic : MvContextType("MOVE_FILE", "Move", EverywhereContextType::class) {
35+
class Generic: MvContextType("Move") {
4236
override fun isInContext(element: PsiElement) = true
4337
}
4438

45-
class Module : MvContextType("MOVE_MODULE", "Module", Generic::class) {
46-
override fun isInContext(element: PsiElement): Boolean
47-
// inside MvModuleDef
48-
= owner(element) is MvModule
39+
class Module: MvContextType("Module") {
40+
override fun isInContext(element: PsiElement): Boolean = owner(element) is MvModule
4941
}
5042

51-
class Block : MvContextType("MOVE_BLOCK", "Block", Generic::class) {
52-
override fun isInContext(element: PsiElement): Boolean
53-
// inside MvCodeBlock
54-
= owner(element) is MvCodeBlock
43+
class Block: MvContextType("Block") {
44+
override fun isInContext(element: PsiElement): Boolean = owner(element) is MvCodeBlock
5545
}
5646

5747
companion object {

src/main/kotlin/org/move/utils/AsyncParameterInfoHandlerBase.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import java.util.concurrent.Executor
1919
*/
2020
abstract class AsyncParameterInfoHandlerBase<ParameterOwner : PsiElement, ParameterType : Any> :
2121
ParameterInfoHandler<ParameterOwner, ParameterType> {
22+
2223
abstract fun findTargetElement(file: PsiFile, offset: Int): ParameterOwner?
2324

2425
/**

0 commit comments

Comments
 (0)