Added inspection for unresolved symbols, macros and labels.

This commit is contained in:
2021-08-09 11:26:13 +02:00
parent a3f7ddb4f7
commit 431caf64fd
11 changed files with 124 additions and 10 deletions
@@ -0,0 +1,48 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiPolyVariantReference
import de.platon42.intellij.plugins.m68k.psi.M68kMacroCall
import de.platon42.intellij.plugins.m68k.psi.M68kSymbolReference
import de.platon42.intellij.plugins.m68k.psi.M68kVisitor
import de.platon42.intellij.plugins.m68k.refs.M68kGlobalLabelSymbolReference
class M68kUnresolvedReferenceInspection : AbstractBaseM68kLocalInspectionTool() {
companion object {
private const val DISPLAY_NAME = "Unresolved label/symbol/macro reference"
}
override fun getDisplayName() = DISPLAY_NAME
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : M68kVisitor() {
override fun visitMacroCall(macroCall: M68kMacroCall) {
val reference = macroCall.reference as? PsiPolyVariantReference ?: return
val resolve = reference.multiResolve(false)
if (resolve.isEmpty()) {
holder.registerProblem(reference)
}
}
override fun visitSymbolReference(symbolReference: M68kSymbolReference) {
val references = symbolReference.references ?: return
if (references.isEmpty()) return
val resolve = references.mapNotNull { it as? PsiPolyVariantReference }
.firstNotNullOfOrNull { it.multiResolve(false).ifEmpty { null } }
if (resolve == null) {
// TODO currently, because macro invocations are not evaluated, mark missing symbols only as weak warning
val makeWeak = references.any { it is M68kGlobalLabelSymbolReference }
if (makeWeak) {
holder.registerProblem(references.first(), ProblemHighlightType.WEAK_WARNING)
} else {
holder.registerProblem(references.first())
}
}
}
}
}
}
@@ -7,6 +7,10 @@ import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
abstract class M68kMacroCallMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kMacroCall {
override fun getReference(): PsiReference? {
return references.firstOrNull()
}
override fun getReferences(): Array<PsiReference> {
return ReferenceProvidersRegistry.getReferencesFromProviders(this)
}
@@ -7,6 +7,10 @@ import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
abstract class M68kPreprocessorDirectiveMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kPreprocessorDirective {
override fun getReference(): PsiReference? {
return references.firstOrNull()
}
override fun getReferences(): Array<PsiReference> {
return ReferenceProvidersRegistry.getReferencesFromProviders(this)
}
@@ -7,6 +7,10 @@ import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
abstract class M68kSymbolReferenceMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kSymbolReference {
override fun getReference(): PsiReference? {
return references.firstOrNull()
}
override fun getReferences(): Array<PsiReference> {
return ReferenceProvidersRegistry.getReferencesFromProviders(this)
}
@@ -1,5 +1,6 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
@@ -14,11 +15,15 @@ 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)) {
class M68kLocalLabelReference(element: M68kSymbolReference) :
PsiPolyVariantReferenceBase<M68kSymbolReference>(element, TextRange(0, element.textLength)),
EmptyResolveMessageProvider {
companion object {
val INSTANCE = Resolver()
private const val UNRESOLVED_MESSAGE_PATTERN = "Cannot resolve local label ''{0}''"
fun findLocalLabels(element: M68kSymbolReference, predicate: (M68kLocalLabel) -> Boolean): List<M68kLocalLabel> {
val statement = PsiTreeUtil.getStubOrPsiParentOfType(element, M68kStatement::class.java)!!
val results = SmartList<M68kLocalLabel>()
@@ -42,6 +47,8 @@ class M68kLocalLabelReference(element: M68kSymbolReference) : PsiPolyVariantRefe
}
}
override fun getUnresolvedMessagePattern() = UNRESOLVED_MESSAGE_PATTERN
class Resolver : ResolveCache.PolyVariantResolver<M68kLocalLabelReference> {
override fun resolve(ref: M68kLocalLabelReference, incompleteCode: Boolean): Array<ResolveResult> {
val refName = ref.element.symbolName
@@ -1,5 +1,6 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementResolveResult
@@ -14,12 +15,16 @@ import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.stubs.M68kMacroDefinitionStubIndex
class M68kMacroReference(element: M68kMacroCall) :
PsiPolyVariantReferenceBase<M68kMacroCall>(element, TextRange(0, element.macroName.length)) {
PsiPolyVariantReferenceBase<M68kMacroCall>(element, TextRange(0, element.macroName.length)), EmptyResolveMessageProvider {
companion object {
val INSTANCE = Resolver()
private const val UNRESOLVED_MESSAGE_PATTERN = "Cannot resolve macro ''{0}''"
}
override fun getUnresolvedMessagePattern() = UNRESOLVED_MESSAGE_PATTERN
class Resolver : ResolveCache.PolyVariantResolver<M68kMacroReference> {
override fun resolve(ref: M68kMacroReference, incompleteCode: Boolean): Array<ResolveResult> {
val macroName = ref.element.macroName
+3
View File
@@ -61,6 +61,9 @@
<localInspection implementationClass="de.platon42.intellij.plugins.m68k.inspections.M68kUnexpectedConditionalInstructionInspection"
displayName="Unaffected condition codes before conditional instruction" groupName="M68k"
enabledByDefault="true" level="WARNING"/>
<localInspection implementationClass="de.platon42.intellij.plugins.m68k.inspections.M68kUnresolvedReferenceInspection"
displayName="Unresolved label/symbol/macro reference" groupName="M68k"
enabledByDefault="true" level="WARNING"/>
</extensions>
<actions>
@@ -0,0 +1,8 @@
<html>
<body>
Checks if references to symbols, macros, global and local labels are resolvable.
<!-- tooltip end -->
<p>Currently, issues a weak warning for global labels or symbols as those
can be defined via macros, which are not evaluated right now</p>
</body>
</html>
@@ -0,0 +1,29 @@
package de.platon42.intellij.plugins.m68k.inspections
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import de.platon42.intellij.jupiter.MyFixture
import org.junit.jupiter.api.Test
internal class M68kUnresolvedReferenceInspectionTest : AbstractInspectionTest() {
@Test
internal fun shows_warning_on_undefined_symbol_label(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.enableInspections(M68kUnresolvedReferenceInspection::class.java)
myFixture.configureByText("unresolvedref.asm", " bra foobar")
assertHighlightings(myFixture, 1, "Cannot resolve symbol 'foobar'")
}
@Test
internal fun shows_warning_on_undefined_local_label(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.enableInspections(M68kUnresolvedReferenceInspection::class.java)
myFixture.configureByText("unresolvedref.asm", " bra .foobar")
assertHighlightings(myFixture, 1, "Cannot resolve local label '.foobar'")
}
@Test
internal fun shows_warning_on_undefined_macro(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.enableInspections(M68kUnresolvedReferenceInspection::class.java)
myFixture.configureByText("unresolvedref.asm", " foobar")
assertHighlightings(myFixture, 1, "Cannot resolve macro 'foobar'")
}
}