Added local label reference (not final yet), but referencing kind of works.

This commit is contained in:
Chris Hodges 2021-07-19 12:08:47 +02:00
parent 6073cd86ac
commit 66fa728a45
14 changed files with 244 additions and 72 deletions

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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

View File

@ -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('$')
}
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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))
}
}
}

View File

@ -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)
}
}
}

View File

@ -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$")
}
}

View 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

View File

@ -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