diff --git a/src/main/java/org/jastadd/tooling/RelAstGrammarAnnotator.java b/src/main/java/org/jastadd/tooling/RelAstGrammarAnnotator.java index a103a37ce02e5b0734671e9742228fe9c45b0221..ce192474421aee6d2ec2e493125be76575a2572f 100644 --- a/src/main/java/org/jastadd/tooling/RelAstGrammarAnnotator.java +++ b/src/main/java/org/jastadd/tooling/RelAstGrammarAnnotator.java @@ -6,50 +6,31 @@ import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; -import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; -import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.javadoc.PsiDocTag; +import org.jastadd.tooling.psi.RelAstGrammarComponent; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.jastadd.tooling.RelAstGrammarUtil.asReferenceToTypeDecl; - public class RelAstGrammarAnnotator implements Annotator { @Override public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { - Optional<PsiClass> classOptional = asReferenceToTypeDecl(element); - - if (classOptional.isEmpty()) { - return; - } - - PsiDocComment docComment = classOptional.get().getDocComment(); - assert docComment != null; // asReferenceToTypeDecl ensures this is not null - - PsiDocTag declaredAtTag = docComment.findTagByName("declaredat"); - if (declaredAtTag == null) { - return; - } - String declaredAt = Arrays.stream(declaredAtTag.getDataElements()).map(PsiElement::getText).collect(Collectors.joining()); - - PsiDocTag productionTag = docComment.findTagByName("astdecl"); - if (productionTag == null) { - return; + if (element instanceof RelAstGrammarComponent) { + RelAstGrammarComponent component = (RelAstGrammarComponent) element; + if (component.getTypeReference() != null && component.getDeclaredName() != null) { + String name = component.getDeclaredName().getText(); + if (name != null && !name.equals("") && name.equals(component.getTypeReference().getName())) { + holder.newAnnotation(HighlightSeverity.WEAK_WARNING, "Redundant name") + .range(component.getDeclaredName().getTextRange()) + .highlightType(ProblemHighlightType.WEAK_WARNING) + .textAttributes(DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE) + .tooltip("When the name of a component is the same as its type, it can be omitted.") + .withFix(new RelAstGrammarRemoveRedundantComponentNameFix(component)) + .create(); + } + } } - String production = Arrays.stream(productionTag.getDataElements()).map(PsiElement::getText).collect(Collectors.joining()); - holder.newAnnotation(HighlightSeverity.INFORMATION, "JastAdd Nonterminal: " + production) - .range(element.getTextRange()) - .highlightType(ProblemHighlightType.INFORMATION) - .textAttributes(DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE) - .tooltip("<b>JastAdd Nonterminal</b><br/>Production: <i>" + production + "</i><br/><i>Declared at </i>" + declaredAt) - .create(); } } diff --git a/src/main/java/org/jastadd/tooling/RelAstGrammarJavaAnnotator.java b/src/main/java/org/jastadd/tooling/RelAstGrammarJavaAnnotator.java new file mode 100644 index 0000000000000000000000000000000000000000..5beaeff927d825c7577c940e5c12e87982db8fda --- /dev/null +++ b/src/main/java/org/jastadd/tooling/RelAstGrammarJavaAnnotator.java @@ -0,0 +1,54 @@ +package org.jastadd.tooling; + + +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.openapi.editor.DefaultLanguageHighlighterColors; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.javadoc.PsiDocTag; +import org.jastadd.tooling.psi.RelAstGrammarComponent; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.jastadd.tooling.RelAstGrammarUtil.asReferenceToTypeDecl; + +public class RelAstGrammarJavaAnnotator implements Annotator { + + @Override + public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) { + + Optional<PsiClass> classOptional = asReferenceToTypeDecl(element); + + if (classOptional.isPresent()) { + PsiDocComment docComment = classOptional.get().getDocComment(); + assert docComment != null; // asReferenceToTypeDecl ensures this is not null + + PsiDocTag declaredAtTag = docComment.findTagByName("declaredat"); + if (declaredAtTag == null) { + return; + } + String declaredAt = Arrays.stream(declaredAtTag.getDataElements()).map(PsiElement::getText).collect(Collectors.joining()); + + PsiDocTag productionTag = docComment.findTagByName("astdecl"); + if (productionTag == null) { + return; + } + String production = Arrays.stream(productionTag.getDataElements()).map(PsiElement::getText).collect(Collectors.joining()); + + holder.newAnnotation(HighlightSeverity.INFORMATION, "JastAdd Nonterminal: " + production) + .range(element.getTextRange()) + .highlightType(ProblemHighlightType.INFORMATION) + .textAttributes(DefaultLanguageHighlighterColors.HIGHLIGHTED_REFERENCE) + .tooltip("<b>JastAdd Nonterminal</b><br/>Production: <i>" + production + "</i><br/><i>Declared at </i>" + declaredAt) + .create(); + } + } + +} diff --git a/src/main/java/org/jastadd/tooling/RelAstGrammarRemoveRedundantComponentNameFix.java b/src/main/java/org/jastadd/tooling/RelAstGrammarRemoveRedundantComponentNameFix.java new file mode 100644 index 0000000000000000000000000000000000000000..01a095de0802074bd1561b684c2102a574d89add --- /dev/null +++ b/src/main/java/org/jastadd/tooling/RelAstGrammarRemoveRedundantComponentNameFix.java @@ -0,0 +1,54 @@ +package org.jastadd.tooling; + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +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.jastadd.tooling.parser.RelAstGrammarTypes; +import org.jastadd.tooling.psi.RelAstGrammarComponent; +import org.jetbrains.annotations.NotNull; + +public class RelAstGrammarRemoveRedundantComponentNameFix extends BaseIntentionAction { + + private final RelAstGrammarComponent component; + + public RelAstGrammarRemoveRedundantComponentNameFix(RelAstGrammarComponent component) { + this.component = component; + } + + @NotNull + @Override + public String getText() { + return "Remove the name of component '" + component.getText() + "'"; + } + + @NotNull + @Override + public String getFamilyName() { + return "Edit component"; + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return true; + } + + @Override + public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws + IncorrectOperationException { + PsiElement first = component.getDeclaredName(); + PsiElement last = component.getDeclaredName(); + while (last != null && last.getNode().getElementType() != RelAstGrammarTypes.COL) { + last = last.getNextSibling(); + } + if (last == null) { + throw new IncorrectOperationException("Unable to find ':' in component definition."); + } else { + component.deleteChildRange(first, last); + } + } + + +} diff --git a/src/main/java/org/jastadd/tooling/psi/impl/RelAstGrammarTypeReferenceImplExtension.java b/src/main/java/org/jastadd/tooling/psi/impl/RelAstGrammarTypeReferenceImplExtension.java index 74f719d63b2e0c086a2be79132133eb4bba65919..3b44b50ecc4e58eb33673bc27a9b6211baed5011 100644 --- a/src/main/java/org/jastadd/tooling/psi/impl/RelAstGrammarTypeReferenceImplExtension.java +++ b/src/main/java/org/jastadd/tooling/psi/impl/RelAstGrammarTypeReferenceImplExtension.java @@ -19,6 +19,7 @@ public class RelAstGrammarTypeReferenceImplExtension extends RelAstGrammarNamedE } public PsiElement setName(@NotNull String newName) { + // FIXME this can break the grammar when the type is used in an unnamed component (and in many other cases probably) ASTNode keyNode = getNode().getFirstChildNode(); if (keyNode != null) { RelAstGrammarTypeReference name = RelAstGrammarElementFactory.createTypeReference(getProject(), newName); diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index ce813c6995c0b380f7114c7d75f4800214bcfe76..2263a9a4ae142caa59dc341419b0e4437a1cffcf 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -20,7 +20,9 @@ <colorSettingsPage implementation="org.jastadd.tooling.RelAstGrammarColorSettingsPage"/> - <annotator language="JAVA" implementationClass="org.jastadd.tooling.RelAstGrammarAnnotator"/> + <annotator language="JAVA" implementationClass="org.jastadd.tooling.RelAstGrammarJavaAnnotator"/> + + <annotator language="JastAddGrammar" implementationClass="org.jastadd.tooling.RelAstGrammarAnnotator"/> <codeInsight.lineMarkerProvider language="JAVA" implementationClass="org.jastadd.tooling.RelAstGrammarLineMarkerProvider"/>