-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add annotations for unresolved references and unused declarations, im…
…proved helpers for working with numeric literals.
- Loading branch information
Showing
14 changed files
with
330 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
src/main/java/org/ca65/action/DisableProjectReferenceCheckingIntentionAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.ca65.action; | ||
|
||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; | ||
import com.intellij.codeInsight.intention.IntentionAction; | ||
import com.intellij.codeInspection.util.IntentionFamilyName; | ||
import com.intellij.codeInspection.util.IntentionName; | ||
import com.intellij.openapi.editor.Editor; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.psi.PsiFile; | ||
import com.intellij.util.IncorrectOperationException; | ||
import org.ca65.Asm6502Bundle; | ||
import org.ca65.config.AsmConfiguration; | ||
import org.ca65.helpers.Cpu; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class DisableProjectReferenceCheckingIntentionAction implements IntentionAction { | ||
|
||
public DisableProjectReferenceCheckingIntentionAction() { | ||
} | ||
|
||
@Override | ||
public @IntentionName @NotNull String getText() { | ||
return Asm6502Bundle.message("INTN.NAME.disable.reference.checking"); | ||
} | ||
|
||
@Override | ||
public @NotNull @IntentionFamilyName String getFamilyName() { | ||
return Asm6502Bundle.message("INTN.NAME.disable.reference.checking"); | ||
} | ||
|
||
@Override | ||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { | ||
AsmConfiguration.getInstance(project).setReferenceCheckingEnabled(false); | ||
DaemonCodeAnalyzer.getInstance(project).restart(); | ||
} | ||
|
||
@Override | ||
public boolean startInWriteAction() { | ||
return false; | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
src/main/java/org/ca65/action/PadNumberIntentionAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package org.ca65.action; | ||
|
||
import com.intellij.codeInsight.intention.IntentionAction; | ||
import com.intellij.codeInspection.util.IntentionFamilyName; | ||
import com.intellij.codeInspection.util.IntentionName; | ||
import com.intellij.openapi.editor.Editor; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.PsiFile; | ||
import com.intellij.util.IncorrectOperationException; | ||
import org.ca65.Asm6502Bundle; | ||
import org.ca65.psi.AsmElementFactory; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class PadNumberIntentionAction implements IntentionAction { | ||
private final PsiElement existingElement; | ||
private final String suggestedReplacement; | ||
|
||
public PadNumberIntentionAction(PsiElement existingElement, String suggestedReplacement) { | ||
this.existingElement = existingElement; | ||
this.suggestedReplacement = suggestedReplacement; | ||
} | ||
|
||
@Override | ||
public @IntentionName @NotNull String getText() { | ||
return Asm6502Bundle.message("INTN.pad.number", this.suggestedReplacement); | ||
} | ||
|
||
@Override | ||
public @NotNull @IntentionFamilyName String getFamilyName() { | ||
return Asm6502Bundle.message("INTN.NAME.pad.number"); | ||
} | ||
|
||
@Override | ||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { | ||
PsiElement newLiteral = AsmElementFactory.createNumericLiteral(project, suggestedReplacement); | ||
existingElement.replace(newLiteral); | ||
} | ||
|
||
@Override | ||
public boolean startInWriteAction() { | ||
return true; | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
src/main/java/org/ca65/annotator/AsmNumericLiteralAnnotator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package org.ca65.annotator; | ||
|
||
import com.intellij.codeInspection.LocalQuickFix; | ||
import com.intellij.codeInspection.ProblemHighlightType; | ||
import com.intellij.lang.annotation.AnnotationHolder; | ||
import com.intellij.lang.annotation.Annotator; | ||
import com.intellij.lang.annotation.HighlightSeverity; | ||
import com.intellij.psi.PsiElement; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.ca65.Asm6502Bundle; | ||
import org.ca65.action.IntentionActionUtil; | ||
import org.ca65.action.PadNumberIntentionAction; | ||
import org.ca65.psi.AsmNumericLiteral; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
/** | ||
* Provide weak warnings for hex and binary literals which are not whole bytes, eg. 7-digit binary numbers. | ||
*/ | ||
public class AsmNumericLiteralAnnotator implements Annotator { | ||
@Override | ||
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { | ||
if(!(element instanceof AsmNumericLiteral)) { | ||
return; | ||
} | ||
// Separate checks for hex vs binary literals | ||
String elementText = element.getText(); | ||
if(elementText.startsWith("$") &&elementText.length() > 1) { | ||
annotateHex(element, holder, elementText.substring(1)); | ||
} | ||
if(elementText.startsWith("%") &&elementText.length() > 1) { | ||
annotateBinary(element, holder, elementText.substring(1)); | ||
} | ||
} | ||
|
||
private void annotateBinary(PsiElement element, AnnotationHolder holder, String binString) { | ||
int len = binString.length(); | ||
int remainder = binString.length() % 8; | ||
if(remainder == 0) { | ||
return; | ||
} | ||
String suggestedReplacement = "%" + StringUtils.leftPad(binString, (len + 8) - remainder, "0"); | ||
holder.newAnnotation(HighlightSeverity.WEAK_WARNING, Asm6502Bundle.message("INSPECT.binary.literal.length", element.getText())) | ||
.range(element.getTextRange()) | ||
.highlightType(ProblemHighlightType.WEAK_WARNING) | ||
.withFix(new PadNumberIntentionAction(element, suggestedReplacement)) | ||
.create(); | ||
} | ||
|
||
private void annotateHex(PsiElement element, AnnotationHolder holder, String hexString) { | ||
if(hexString.length() % 2 == 0) { | ||
return; | ||
} | ||
String suggestedReplacement = "$0" + hexString; | ||
holder.newAnnotation(HighlightSeverity.WEAK_WARNING, Asm6502Bundle.message("INSPECT.hex.literal.length", element.getText())) | ||
.range(element.getTextRange()) | ||
.highlightType(ProblemHighlightType.WEAK_WARNING) | ||
.withFix(new PadNumberIntentionAction(element, suggestedReplacement)) | ||
.create(); | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
src/main/java/org/ca65/annotator/AsmUnresolvedReferenceAnnotator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package org.ca65.annotator; | ||
|
||
import com.intellij.codeInspection.ProblemHighlightType; | ||
import com.intellij.lang.annotation.AnnotationHolder; | ||
import com.intellij.lang.annotation.Annotator; | ||
import com.intellij.lang.annotation.HighlightSeverity; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.PsiFile; | ||
import com.intellij.psi.PsiReference; | ||
import org.ca65.Asm6502Bundle; | ||
import org.ca65.action.DisableProjectReferenceCheckingIntentionAction; | ||
import org.ca65.config.AsmConfiguration; | ||
import org.ca65.psi.AsmDotexpr; | ||
import org.ca65.psi.impl.AsmIdentifierrImpl; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
/** | ||
* Highlight references to symbols which are not defined in current file. Does not work with includes. | ||
**/ | ||
public class AsmUnresolvedReferenceAnnotator implements Annotator { | ||
@Override | ||
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { | ||
if (!AsmConfiguration.getInstance(element.getProject()).isReferenceCheckingEnabled()) { | ||
return; // Reference checking is disabled | ||
} | ||
if (!(element instanceof AsmIdentifierrImpl)) { | ||
return; | ||
} | ||
if (isInMacroDef(element)) { | ||
// Identifiers used in macros are not correct | ||
return; | ||
} | ||
PsiReference reference = element.getReference(); | ||
if (reference != null && reference.resolve() != null) { | ||
return; // definition exists | ||
} | ||
String elementName = ((AsmIdentifierrImpl) element).getName(); | ||
holder.newAnnotation(HighlightSeverity.ERROR, Asm6502Bundle.message("INSPECT.unresolved.reference", elementName)) | ||
.range(element.getTextRange()) | ||
.highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) | ||
.withFix(new DisableProjectReferenceCheckingIntentionAction()) | ||
.create(); | ||
} | ||
|
||
private boolean isInMacroDef(PsiElement element) { | ||
// Go up until element parent is file | ||
while (element != null && !(element.getParent() instanceof PsiFile)) { | ||
element = element.getParent(); | ||
} | ||
if (element == null) { | ||
return false; | ||
} | ||
// Make a guess for performance: most macros are quite short. Assume we are *not* in a macro if we don't | ||
// find a '.macro' statement after some reasonable number of elements. | ||
int iterMax = 250; | ||
int i = 0; | ||
// Not a nested structure (really should be..), so we scan backwards from here. | ||
// if we hit a .endmacro or start of file, we are not in a macro. | ||
// if we hit a .macro, we are. | ||
while (element != null && i < iterMax) { | ||
if (element instanceof AsmDotexpr) { | ||
String elementText = element.getFirstChild() == null ? element.getText() : element.getFirstChild().getText(); | ||
if (".macro".equalsIgnoreCase(elementText) || ".mac".equalsIgnoreCase(elementText)) { | ||
return true; | ||
} else if (".endmacro".equalsIgnoreCase(elementText) || ".endmac".equalsIgnoreCase(elementText)) { | ||
return false; | ||
} | ||
} | ||
element = element.getPrevSibling(); | ||
i++; | ||
} | ||
return false; | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
src/main/java/org/ca65/annotator/AsmUnusedReferenceAnnotator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package org.ca65.annotator; | ||
|
||
import com.intellij.codeInspection.ProblemHighlightType; | ||
import com.intellij.lang.annotation.AnnotationHolder; | ||
import com.intellij.lang.annotation.Annotator; | ||
import com.intellij.lang.annotation.HighlightSeverity; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.PsiNameIdentifierOwner; | ||
import com.intellij.psi.PsiReference; | ||
import com.intellij.psi.search.GlobalSearchScope; | ||
import com.intellij.psi.search.searches.ReferencesSearch; | ||
import com.intellij.util.Query; | ||
import org.ca65.Asm6502Bundle; | ||
import org.ca65.action.DisableProjectReferenceCheckingIntentionAction; | ||
import org.ca65.config.AsmConfiguration; | ||
import org.ca65.psi.AsmLabelDefinition; | ||
import org.ca65.psi.impl.AsmIdentifierDefinitionImpl; | ||
import org.ca65.psi.impl.AsmLabelDefinitionImpl; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
/** | ||
* Highlight unused definitions in file. Does not catch symbols defined in includes, and is not efficient at all. | ||
**/ | ||
public class AsmUnusedReferenceAnnotator implements Annotator { | ||
@Override | ||
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { | ||
if (!AsmConfiguration.getInstance(element.getProject()).isReferenceCheckingEnabled()) { | ||
return; // Reference checking is disabled | ||
} | ||
if (!(element instanceof AsmLabelDefinitionImpl || element instanceof AsmIdentifierDefinitionImpl)) { | ||
return; | ||
} | ||
if (isReferenced((PsiNameIdentifierOwner) element)) { | ||
return; | ||
} | ||
if(element instanceof AsmLabelDefinitionImpl && ((AsmLabelDefinition) element).getNameIdentifier() == null) { | ||
return; // References to anonymous labels don't work | ||
} | ||
String elementName = ((PsiNameIdentifierOwner) element).getName(); | ||
holder.newAnnotation(HighlightSeverity.WEAK_WARNING, Asm6502Bundle.message("INSPECT.unused.reference", elementName)) | ||
.range(element.getTextRange()) | ||
.highlightType(ProblemHighlightType.LIKE_UNUSED_SYMBOL) | ||
.withFix(new DisableProjectReferenceCheckingIntentionAction()) | ||
.create(); | ||
} | ||
|
||
private boolean isReferenced(PsiNameIdentifierOwner element) { | ||
final Query<PsiReference> refs = ReferencesSearch.search(element, GlobalSearchScope.fileScope(element.getContainingFile()), false); | ||
if (element instanceof AsmLabelDefinitionImpl) { | ||
// Simple case | ||
PsiReference firstReference = refs.findFirst(); | ||
return firstReference != null; | ||
} | ||
// These turn up references to themselves, using text range to skip. | ||
for (PsiReference ref : refs) { | ||
if (!ref.getAbsoluteRange().equals(element.getTextRange())) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.