Added local label reference (not final yet), but referencing kind of works.
This commit is contained in:
parent
6073cd86ac
commit
66fa728a45
@ -2,7 +2,13 @@
|
||||
package de.platon42.intellij.plugins.m68k.psi;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface M68kSymbolReference extends PsiElement {
|
||||
|
||||
@NotNull
|
||||
String getSymbolName();
|
||||
|
||||
boolean isLocalLabelRef();
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package de.platon42.intellij.plugins.m68k.psi.impl;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kPsiImplUtil;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReferenceMixin;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class M68kSymbolReferenceImpl extends ASTWrapperPsiElement implements M68kSymbolReference {
|
||||
public class M68kSymbolReferenceImpl extends M68kSymbolReferenceMixin implements M68kSymbolReference {
|
||||
|
||||
public M68kSymbolReferenceImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
@ -24,4 +25,15 @@ public class M68kSymbolReferenceImpl extends ASTWrapperPsiElement implements M68
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getSymbolName() {
|
||||
return M68kPsiImplUtil.getSymbolName(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocalLabelRef() {
|
||||
return M68kPsiImplUtil.isLocalLabelRef(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
package de.platon42.intellij.plugins.m68k
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.util.IconLoader
|
||||
|
||||
object M68kIcons {
|
||||
val FILE = IconLoader.getIcon("/icons/FileType_m68k.svg", javaClass)
|
||||
val LOCAL_LABEL = AllIcons.Nodes.AbstractMethod
|
||||
val GLOBAL_LABEL = AllIcons.Nodes.Method
|
||||
val SYMBOL_DEF = AllIcons.Nodes.Constant
|
||||
}
|
@ -153,6 +153,8 @@ GlobalLabel ::= GLOBAL_LABEL_DEF COLON* {
|
||||
extends = Label
|
||||
implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement"
|
||||
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabelMixin"
|
||||
// elementTypeFactory = "de.platon42.intellij.plugins.m68k.stubs.M68kStubElementTypeFactory.stubFactory"
|
||||
// stubClass = "de.platon42.intellij.plugins.m68k.stubs.M68kGlobalLabelStub"
|
||||
methods = [getName setName getNameIdentifier]
|
||||
}
|
||||
|
||||
@ -179,7 +181,13 @@ private PreprocessorOperand ::= expr
|
||||
|
||||
private PlainOperands ::= STRINGLIT (SEPARATOR STRINGLIT)*
|
||||
|
||||
SymbolReference ::= SYMBOL // TODO This should probably be a ILazyParseableElementType, no idea how to implement that yet
|
||||
// TODO This should probably be a ILazyParseableElementType, no idea how to implement that yet
|
||||
SymbolReference ::= SYMBOL {
|
||||
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kSymbolReferenceMixin"
|
||||
methods = [getSymbolName isLocalLabelRef]
|
||||
// implements = "com.intellij.model.psi.PsiExternalReferenceHost"
|
||||
}
|
||||
|
||||
ProgramCounterReference ::= CURRENT_PC_SYMBOL
|
||||
|
||||
DataRegister ::= DREG {
|
||||
|
@ -2,7 +2,12 @@ package de.platon42.intellij.plugins.m68k.psi
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import de.platon42.intellij.plugins.m68k.M68kIcons
|
||||
import javax.swing.Icon
|
||||
|
||||
abstract class M68kLocalLabelMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kLocalLabel {
|
||||
|
||||
override fun getIcon(flags: Int): Icon? {
|
||||
return M68kIcons.LOCAL_LABEL
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package de.platon42.intellij.plugins.m68k.psi;
|
||||
package de.platon42.intellij.plugins.m68k.psi
|
||||
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import com.intellij.psi.NavigatablePsiElement
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
|
||||
public interface M68kNamedElement extends PsiNameIdentifierOwner {
|
||||
}
|
||||
interface M68kNamedElement : PsiNameIdentifierOwner, NavigatablePsiElement
|
@ -45,7 +45,6 @@ object M68kPsiImplUtil {
|
||||
|
||||
|
||||
// Symbol Definition
|
||||
|
||||
@JvmStatic
|
||||
fun getName(element: M68kSymbolDefinition): String? = element.firstChild.text
|
||||
|
||||
@ -62,4 +61,14 @@ object M68kPsiImplUtil {
|
||||
@JvmStatic
|
||||
fun getNameIdentifier(element: M68kSymbolDefinition): PsiElement = element.firstChild
|
||||
|
||||
|
||||
// Symbol Reference
|
||||
@JvmStatic
|
||||
fun getSymbolName(element: M68kSymbolReference): String = element.firstChild.text
|
||||
|
||||
@JvmStatic
|
||||
fun isLocalLabelRef(element: M68kSymbolReference): Boolean {
|
||||
val text = element.firstChild.text
|
||||
return text.startsWith('.') || text.endsWith('$')
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package de.platon42.intellij.plugins.m68k.psi
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
|
||||
|
||||
abstract class M68kSymbolReferenceMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kSymbolReference {
|
||||
|
||||
override fun getReferences(): Array<PsiReference> {
|
||||
return ReferenceProvidersRegistry.getReferencesFromProviders(this)
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package de.platon42.intellij.plugins.m68k.refs
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementResolveResult
|
||||
import com.intellij.psi.PsiPolyVariantReferenceBase
|
||||
import com.intellij.psi.ResolveResult
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.SmartList
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference
|
||||
|
||||
class M68kLocalLabelReference(element: M68kSymbolReference) : PsiPolyVariantReferenceBase<M68kSymbolReference>(element, TextRange(0, element.textLength)) {
|
||||
|
||||
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> {
|
||||
val refName = myElement.symbolName
|
||||
|
||||
return findLocalLabels { it.name == refName }
|
||||
.map { PsiElementResolveResult(it) }
|
||||
.toTypedArray()
|
||||
}
|
||||
|
||||
override fun resolve(): PsiElement? {
|
||||
val resolveResults = multiResolve(false)
|
||||
return resolveResults.singleOrNull()?.element
|
||||
}
|
||||
|
||||
override fun getVariants(): Array<Any> {
|
||||
return findLocalLabels { true }
|
||||
.map { LookupElementBuilder.createWithIcon(it) }
|
||||
.toTypedArray()
|
||||
}
|
||||
|
||||
private fun findLocalLabels(predicate: (M68kLocalLabel) -> Boolean): List<M68kLocalLabel> {
|
||||
val statement = PsiTreeUtil.getStubOrPsiParentOfType(element, M68kStatement::class.java)!!
|
||||
val results: MutableList<M68kLocalLabel> = SmartList()
|
||||
// go backward
|
||||
var currentStatement = PsiTreeUtil.getPrevSiblingOfType(statement, M68kStatement::class.java)
|
||||
while (currentStatement != null) {
|
||||
val child = currentStatement.firstChild
|
||||
if (child is M68kGlobalLabel) break
|
||||
if (child is M68kLocalLabel && predicate.invoke(child)) results.add(child)
|
||||
currentStatement = PsiTreeUtil.getPrevSiblingOfType(currentStatement, M68kStatement::class.java)
|
||||
}
|
||||
// go forward
|
||||
currentStatement = statement
|
||||
while (currentStatement != null) {
|
||||
val child = currentStatement.firstChild
|
||||
if (child is M68kGlobalLabel) break
|
||||
if (child is M68kLocalLabel && predicate.invoke(child)) results.add(child)
|
||||
currentStatement = PsiTreeUtil.getNextSiblingOfType(currentStatement, M68kStatement::class.java)
|
||||
}
|
||||
return results
|
||||
}
|
||||
}
|
@ -3,26 +3,23 @@ package de.platon42.intellij.plugins.m68k.refs
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.util.ProcessingContext
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kRefExpr
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference
|
||||
|
||||
class M68kReferenceContributor : PsiReferenceContributor() {
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kRefExpr::class.java), object : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return emptyArray()
|
||||
}
|
||||
})
|
||||
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kGlobalLabel::class.java), object : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return emptyArray()
|
||||
}
|
||||
})
|
||||
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kLocalLabel::class.java), object : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
return emptyArray()
|
||||
}
|
||||
})
|
||||
|
||||
companion object {
|
||||
val localLabelReferenceProvider = LocalLabelReferenceProvider()
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kSymbolReference::class.java), localLabelReferenceProvider)
|
||||
}
|
||||
|
||||
class LocalLabelReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
|
||||
val symbolReference = element as M68kSymbolReference
|
||||
if (!symbolReference.isLocalLabelRef) return emptyArray()
|
||||
return arrayOf(M68kLocalLabelReference(symbolReference))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +1,59 @@
|
||||
package de.platon42.intellij.plugins.m68k.scanner;
|
||||
package de.platon42.intellij.plugins.m68k.scanner
|
||||
|
||||
import com.intellij.lang.cacheBuilder.DefaultWordsScanner;
|
||||
import com.intellij.lang.cacheBuilder.WordsScanner;
|
||||
import com.intellij.lang.findUsages.FindUsagesProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import de.platon42.intellij.plugins.m68k.lexer.M68kLexer;
|
||||
import de.platon42.intellij.plugins.m68k.lexer.M68kLexerPrefs;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel;
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kTypes;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.lang.cacheBuilder.DefaultWordsScanner
|
||||
import com.intellij.lang.cacheBuilder.WordsScanner
|
||||
import com.intellij.lang.findUsages.FindUsagesProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import de.platon42.intellij.plugins.m68k.lexer.M68kLexer
|
||||
import de.platon42.intellij.plugins.m68k.lexer.M68kLexerPrefs
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinition
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.annotations.NonNls
|
||||
|
||||
public class M68kFindUsagesProvider implements FindUsagesProvider {
|
||||
class M68kFindUsagesProvider : FindUsagesProvider {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WordsScanner getWordsScanner() {
|
||||
return new DefaultWordsScanner(new M68kLexer(new M68kLexerPrefs()), // FIXME Oh no! More Prefs!
|
||||
TokenSet.create(M68kTypes.SYMBOLDEF, M68kTypes.GLOBAL_LABEL_DEF, M68kTypes.LOCAL_LABEL_DEF, M68kTypes.SYMBOL),
|
||||
TokenSet.create(M68kTypes.COMMENT),
|
||||
TokenSet.create(M68kTypes.STRINGLIT),
|
||||
TokenSet.EMPTY);
|
||||
override fun getWordsScanner(): WordsScanner {
|
||||
return DefaultWordsScanner(
|
||||
M68kLexer(M68kLexerPrefs()), // FIXME Oh no! More Prefs!
|
||||
TokenSet.create(M68kTypes.SYMBOLDEF, M68kTypes.GLOBAL_LABEL_DEF, M68kTypes.LOCAL_LABEL_DEF, M68kTypes.SYMBOL),
|
||||
TokenSet.create(M68kTypes.COMMENT),
|
||||
TokenSet.create(M68kTypes.STRINGLIT),
|
||||
TokenSet.EMPTY
|
||||
)
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
|
||||
return psiElement instanceof PsiNamedElement;
|
||||
override fun canFindUsagesFor(psiElement: PsiElement): Boolean {
|
||||
return psiElement is PsiNamedElement
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable @NonNls String getHelpId(@NotNull PsiElement psiElement) {
|
||||
return null;
|
||||
override fun getHelpId(psiElement: PsiElement): @NonNls String? {
|
||||
return null
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nls @NotNull String getType(@NotNull PsiElement element) {
|
||||
if (element instanceof M68kGlobalLabel) {
|
||||
return "global label";
|
||||
override fun getType(element: PsiElement): @Nls String {
|
||||
return when (element) {
|
||||
is M68kGlobalLabel -> "global label"
|
||||
is M68kLocalLabel -> "local label"
|
||||
is M68kSymbolDefinition -> "symbol definition"
|
||||
else -> ""
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nls @NotNull String getDescriptiveName(@NotNull PsiElement element) {
|
||||
if (element instanceof M68kGlobalLabel) {
|
||||
return ((M68kGlobalLabel) element).getName();
|
||||
override fun getDescriptiveName(element: PsiElement): @Nls String {
|
||||
return when (element) {
|
||||
is M68kGlobalLabel -> element.name!!
|
||||
is M68kLocalLabel -> element.name!!
|
||||
is M68kSymbolDefinition -> element.parent.text
|
||||
else -> ""
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nls @NotNull String getNodeText(@NotNull PsiElement element, boolean useFullName) {
|
||||
return getDescriptiveName(element);
|
||||
override fun getNodeText(element: PsiElement, useFullName: Boolean): @Nls String {
|
||||
return getDescriptiveName(element)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package de.platon42.intellij.plugins.m68k.refs
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import de.platon42.intellij.jupiter.LightCodeInsightExtension
|
||||
import de.platon42.intellij.jupiter.MyFixture
|
||||
import de.platon42.intellij.jupiter.TestDataPath
|
||||
import de.platon42.intellij.jupiter.TestDataSubPath
|
||||
import de.platon42.intellij.plugins.m68k.AbstractM68kTest
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
|
||||
@TestDataPath("src/test/resources/references")
|
||||
@TestDataSubPath("labels")
|
||||
@ExtendWith(LightCodeInsightExtension::class)
|
||||
internal class M68kReferenceContributorTest : AbstractM68kTest() {
|
||||
|
||||
@Test
|
||||
internal fun reference_to_dot_local_label(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
// val reference = myFixture.getReferenceAtCaretPositionWithAssertion("dot_local_label.asm")
|
||||
// assertThat(reference.element).isInstanceOf(M68kSym)
|
||||
myFixture.configureByFile("dot_local_label.asm")
|
||||
assertThat(myFixture.elementAtCaret).isInstanceOf(M68kLocalLabel::class.java)
|
||||
.extracting(PsiElement::getText).isEqualTo(".loop")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun reference_to_multiple_conditional_local_label_dollar(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
val reference = myFixture.getReferenceAtCaretPositionWithAssertion("multiple_conditional_local_label_dollar.asm")
|
||||
assertThat(reference.element).isInstanceOf(M68kLocalLabel::class.java)
|
||||
myFixture.configureByFile("multiple_conditional_local_label_dollar.asm")
|
||||
assertThat(myFixture.elementAtCaret).isInstanceOf(M68kLocalLabel::class.java)
|
||||
.extracting(PsiElement::getText).isEqualTo("loop$")
|
||||
}
|
||||
}
|
10
src/test/resources/references/labels/dot_local_label.asm
Normal file
10
src/test/resources/references/labels/dot_local_label.asm
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
main
|
||||
tst.w d1
|
||||
beq.s .skip
|
||||
moveq.l #42,d0
|
||||
.loop move.l d0,(a0)+
|
||||
dbra d0,.l<caret>oop
|
||||
.skip subq.w #1,d1
|
||||
beq.s .loop
|
||||
rts
|
@ -0,0 +1,14 @@
|
||||
|
||||
main
|
||||
tst.w d1
|
||||
beq.s .skip
|
||||
moveq.l #42,d0
|
||||
IFEQ DATAWIDTH=4
|
||||
loop$ move.l d0,(a0)+
|
||||
ELSE
|
||||
loop$ move.w d0,(a0)+
|
||||
ENDC
|
||||
dbra d0,l<caret>oop$
|
||||
.skip subq.w #1,d1
|
||||
beq.s loop$
|
||||
rts
|
Loading…
Reference in New Issue
Block a user