Skip to content

Commit 5b4ffdd

Browse files
committed
feat(navigation): add navigation to parent constant definition and vice versa
Fixes #18
1 parent 5306a64 commit 5b4ffdd

File tree

7 files changed

+166
-4
lines changed

7 files changed

+166
-4
lines changed

src/main/kotlin/org/tonstudio/tact/lang/psi/TactStorageMembersOwner.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ fun TactStorageMembersOwner.fields(): List<TactFieldDefinition> {
2020
return own + inherited
2121
}
2222

23+
fun TactStorageMembersOwner.constants(): List<TactConstDefinition> {
24+
val own = getConstantsList()
25+
val inherited = getInheritedTraits().flatMap { it.traitType.getConstantsList() }
26+
return own + inherited
27+
}
28+
2329
fun TactStorageMembersOwner.name(): String {
2430
val parent = this.parent
2531
if (parent is TactNamedElement) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.tonstudio.tact.lang.search
2+
3+
import com.intellij.openapi.application.QueryExecutorBase
4+
import com.intellij.psi.search.searches.DefinitionsScopedSearch
5+
import com.intellij.util.Processor
6+
import org.tonstudio.tact.lang.psi.*
7+
8+
class TactConstantImplementationsSearch : QueryExecutorBase<TactConstDefinition, DefinitionsScopedSearch.SearchParameters>(true) {
9+
override fun processQuery(
10+
parameters: DefinitionsScopedSearch.SearchParameters,
11+
consumer: Processor<in TactConstDefinition>,
12+
) {
13+
if (!parameters.isCheckDeep) return
14+
15+
val constant = parameters.element as? TactConstDefinition ?: return
16+
val trait = constant.getOwner() as? TactTraitDeclaration ?: return
17+
18+
TactImplementationsSearch().processQuery(DefinitionsScopedSearch.SearchParameters(trait), { t ->
19+
val implementations = t.getConstantsList().filter { c -> c.name == constant.name }
20+
for (implementation in implementations) {
21+
consumer.process(implementation)
22+
}
23+
true
24+
})
25+
}
26+
}

src/main/kotlin/org/tonstudio/tact/lang/search/TactGotoSuperHandler.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.intellij.openapi.editor.Editor
55
import com.intellij.openapi.project.Project
66
import com.intellij.psi.PsiElement
77
import com.intellij.psi.PsiFile
8+
import org.tonstudio.tact.lang.psi.TactConstDefinition
89
import org.tonstudio.tact.lang.psi.TactFile
910
import org.tonstudio.tact.lang.psi.TactFunctionDeclaration
1011

@@ -23,5 +24,8 @@ class TactGotoSuperHandler : LanguageCodeInsightActionHandler {
2324
if (parent is TactFunctionDeclaration) {
2425
showSuperMethodPopup(null, parent)
2526
}
27+
if (parent is TactConstDefinition) {
28+
showSuperConstantPopup(null, parent)
29+
}
2630
}
2731
}

src/main/kotlin/org/tonstudio/tact/lang/search/TactImplementationsProvider.kt

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement
99
import com.intellij.psi.impl.source.tree.LeafPsiElement
1010
import com.intellij.psi.search.searches.DefinitionsScopedSearch
1111
import org.tonstudio.tact.lang.TactTypes
12+
import org.tonstudio.tact.lang.psi.TactConstDefinition
1213
import org.tonstudio.tact.lang.psi.TactFunctionDeclaration
1314
import org.tonstudio.tact.lang.psi.TactNamedElement
1415
import org.tonstudio.tact.lang.psi.TactTraitDeclaration
@@ -35,11 +36,28 @@ class TactImplementationsProvider : LineMarkerProviderDescriptor() {
3536
): Boolean {
3637
if (element !is LeafPsiElement || element.elementType != TactTypes.IDENTIFIER) return true
3738

38-
val func = element.parent as? TactFunctionDeclaration ?: return true
39+
val func = element.parent as? TactFunctionDeclaration
40+
if (func != null) {
41+
return processFunction(func, element, result)
42+
}
43+
44+
val constant = element.parent as? TactConstDefinition
45+
if (constant != null) {
46+
return processConstant(constant, element, result)
47+
}
48+
49+
return false
50+
}
51+
52+
private fun processFunction(
53+
func: TactFunctionDeclaration,
54+
element: LeafPsiElement,
55+
result: MutableCollection<in LineMarkerInfo<*>?>,
56+
): Boolean {
3957
val owner = func.getOwner() ?: return true
4058
if (owner !is TactTraitDeclaration) return true
4159

42-
if (!hasImplementations(func, TactFunctionImplementationsSearch())) return false
60+
if (!hasImplementations(func, TactFunctionImplementationsSearch())) return true
4361

4462
val (action, what) = if (!func.isAbstract) "Overrides" to "override" else "Implementations" to "implemented"
4563

@@ -59,4 +77,33 @@ class TactImplementationsProvider : LineMarkerProviderDescriptor() {
5977
result.add(info)
6078
return false
6179
}
80+
81+
private fun processConstant(
82+
constant: TactConstDefinition,
83+
element: LeafPsiElement,
84+
result: MutableCollection<in LineMarkerInfo<*>?>,
85+
): Boolean {
86+
val owner = constant.getOwner() ?: return true
87+
if (owner !is TactTraitDeclaration) return true
88+
89+
if (!hasImplementations(constant, TactConstantImplementationsSearch())) return true
90+
91+
val (action, what) = "Overrides" to "override"
92+
93+
val info = createInfo(element, { event, elem ->
94+
val named = elem.parent as? TactNamedElement ?: return@createInfo
95+
96+
showPopup(
97+
"$action of $name",
98+
{ size -> "Constant '$name' $what in $size types" },
99+
event,
100+
DefinitionsScopedSearch.SearchParameters(named),
101+
methodRenderer(named),
102+
TactConstantImplementationsSearch(),
103+
)
104+
}, "Go to $action", AllIcons.Gutter.ImplementedMethod, IdeActions.ACTION_GOTO_IMPLEMENTATION)
105+
106+
result.add(info)
107+
return false
108+
}
62109
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.tonstudio.tact.lang.search
2+
3+
import com.intellij.openapi.application.QueryExecutorBase
4+
import com.intellij.psi.search.searches.DefinitionsScopedSearch
5+
import com.intellij.util.CommonProcessors
6+
import com.intellij.util.Processor
7+
import org.tonstudio.tact.lang.psi.TactConstDefinition
8+
import org.tonstudio.tact.lang.psi.TactContractDeclaration
9+
import org.tonstudio.tact.lang.psi.TactTraitDeclaration
10+
import org.tonstudio.tact.lang.psi.constants
11+
12+
fun hasSuperConstant(method: TactConstDefinition): Boolean {
13+
val processor = CommonProcessors.FindFirstProcessor<TactConstDefinition>()
14+
TactSuperConstantSearch().processQuery(DefinitionsScopedSearch.SearchParameters(method), processor)
15+
return processor.isFound
16+
}
17+
18+
class TactSuperConstantSearch : QueryExecutorBase<TactConstDefinition, DefinitionsScopedSearch.SearchParameters>(true) {
19+
override fun processQuery(
20+
parameters: DefinitionsScopedSearch.SearchParameters,
21+
consumer: Processor<in TactConstDefinition>,
22+
) {
23+
if (!parameters.isCheckDeep) return
24+
25+
val const = parameters.element as? TactConstDefinition ?: return
26+
val constName = const.name
27+
28+
val owner = const.getOwner() ?: return
29+
val ownerType = when (owner) {
30+
is TactContractDeclaration -> owner.contractType
31+
is TactTraitDeclaration -> owner.traitType
32+
else -> null
33+
} ?: return
34+
35+
val inheritedTraits = ownerType.getInheritedTraits()
36+
if (inheritedTraits.isEmpty()) return
37+
38+
val superTraitWithConst = inheritedTraits.find { it.traitType.constants().find { const -> const.name == constName } != null }
39+
if (superTraitWithConst == null) return
40+
41+
val superConstant = superTraitWithConst.traitType.constants().find { m -> m.name == constName }
42+
consumer.process(superConstant)
43+
}
44+
}

src/main/kotlin/org/tonstudio/tact/lang/search/TactSuperMarkerProvider.kt

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement
99
import com.intellij.psi.impl.source.tree.LeafPsiElement
1010
import com.intellij.psi.search.searches.DefinitionsScopedSearch
1111
import org.tonstudio.tact.lang.TactTypes
12+
import org.tonstudio.tact.lang.psi.TactConstDefinition
1213
import org.tonstudio.tact.lang.psi.TactFunctionDeclaration
1314
import java.awt.event.MouseEvent
1415

@@ -34,9 +35,9 @@ class TactSuperMarkerProvider : LineMarkerProviderDescriptor() {
3435
) {
3536
if (element !is LeafPsiElement || element.elementType != TactTypes.IDENTIFIER) return
3637

37-
val func = element.parent as? TactFunctionDeclaration ?: return
38+
val func = element.parent as? TactFunctionDeclaration
3839

39-
if (hasSuperMethod(func)) {
40+
if (func != null && hasSuperMethod(func)) {
4041
result.add(
4142
createInfo(
4243
element,
@@ -47,6 +48,19 @@ class TactSuperMarkerProvider : LineMarkerProviderDescriptor() {
4748
)
4849
)
4950
}
51+
52+
val constant = element.parent as? TactConstDefinition
53+
if (constant != null && hasSuperConstant(constant)) {
54+
result.add(
55+
createInfo(
56+
element,
57+
{ e, identifier -> showSuperConstantPopup(e, identifier) },
58+
"Go to Parent Constant",
59+
AllIcons.Gutter.OverridingMethod,
60+
IdeActions.ACTION_GOTO_SUPER,
61+
)
62+
)
63+
}
5064
}
5165
}
5266

@@ -68,3 +82,22 @@ private fun showSuperMethodPopup(e: MouseEvent?, identifier: PsiElement) {
6882
val method = identifier.parent as? TactFunctionDeclaration ?: return
6983
showSuperMethodPopup(e, method)
7084
}
85+
86+
fun showSuperConstantPopup(event: MouseEvent?, constant: TactConstDefinition) {
87+
val name = constant.name
88+
showPopup(
89+
"Implement constant $name",
90+
{
91+
"Constant '$name' Overrides Constant of Trait"
92+
},
93+
event,
94+
DefinitionsScopedSearch.SearchParameters(constant),
95+
methodRenderer(constant),
96+
TactSuperConstantSearch(),
97+
)
98+
}
99+
100+
private fun showSuperConstantPopup(e: MouseEvent?, identifier: PsiElement) {
101+
val method = identifier.parent as? TactConstDefinition ?: return
102+
showSuperConstantPopup(e, method)
103+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,10 @@ Provides official support for <a href="https://tact-lang.org/">Tact</a> programm
120120

121121
<!-- region Searches -->
122122
<definitionsScopedSearch implementation="org.tonstudio.tact.lang.search.TactSuperMethodSearch"/>
123+
<definitionsScopedSearch implementation="org.tonstudio.tact.lang.search.TactSuperConstantSearch"/>
123124
<definitionsScopedSearch implementation="org.tonstudio.tact.lang.search.TactImplementationsSearch"/>
124125
<definitionsScopedSearch implementation="org.tonstudio.tact.lang.search.TactFunctionImplementationsSearch"/>
126+
<definitionsScopedSearch implementation="org.tonstudio.tact.lang.search.TactConstantImplementationsSearch"/>
125127
<codeInsight.lineMarkerProvider language="tact"
126128
implementationClass="org.tonstudio.tact.lang.search.TactSuperMarkerProvider"/>
127129
<codeInsight.lineMarkerProvider language="tact"

0 commit comments

Comments
 (0)