diff --git a/src/main/grammar/Aspect.bnf b/src/main/grammar/Aspect.bnf index f112d4cc3783094fea55c77acce397b4d5b2e943..a11bb754aed3982b9eb69900f59c5b0f63c5df13 100644 --- a/src/main/grammar/Aspect.bnf +++ b/src/main/grammar/Aspect.bnf @@ -215,6 +215,10 @@ type ::= reference_type | primitive_type reference_type ::= ( primitive_type (LBRACKET RBRACKET)+ ) | ( class_or_interface_type (LBRACKET RBRACKET)* ) class_or_interface_type ::= java_identifier type_arguments? (DOT java_identifier type_arguments? )* +{ + extends="org.jastadd.tooling.aspect.psi.impl.JastAddAspectClassOrInterfaceTypeImplExtension" + implements="org.jastadd.tooling.grammar.psi.GrammarNamedElement" +} type_arguments ::= LT (type_argument (COMMA type_argument)* )? GT diff --git a/src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java b/src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java index 139081c5bd629fa49740a22895ebd3b20d25ede7..5d993a175373ee059726139a39179607a5ccb575 100644 --- a/src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java +++ b/src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java @@ -5,6 +5,7 @@ import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.*; import com.intellij.util.ProcessingContext; import org.jastadd.tooling.aspect.psi.JastAddAspectAstTypeName; +import org.jastadd.tooling.aspect.psi.JastAddAspectClassOrInterfaceType; import org.jastadd.tooling.grammar.GrammarReference; import org.jetbrains.annotations.NotNull; @@ -27,6 +28,23 @@ public class AspectReferenceContributor extends PsiReferenceContributor { return PsiReference.EMPTY_ARRAY; } }); + registrar.registerReferenceProvider(PlatformPatterns.psiElement(JastAddAspectClassOrInterfaceType.class), + new PsiReferenceProvider() { + @NotNull + @Override + public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement element, + @NotNull ProcessingContext context) { + JastAddAspectClassOrInterfaceType typeReference = (JastAddAspectClassOrInterfaceType) element; + if (typeReference.getTypeArgumentsList().isEmpty() && typeReference.getJavaIdentifierList().size() == 1) { + String value = typeReference.getJavaIdentifierList().get(0).getText(); + if (value != null) { + TextRange range = new TextRange(0, value.length()); + return new PsiReference[]{new GrammarReference(element, range)}; + } + } + return PsiReference.EMPTY_ARRAY; + } + }); } } diff --git a/src/main/java/org/jastadd/tooling/aspect/psi/AspectElementFactory.java b/src/main/java/org/jastadd/tooling/aspect/psi/AspectElementFactory.java index aa408355232e174d1cef76bcc00cedd323f24e84..575b08a8d95c3e09a06a0849ec22306d4825291b 100644 --- a/src/main/java/org/jastadd/tooling/aspect/psi/AspectElementFactory.java +++ b/src/main/java/org/jastadd/tooling/aspect/psi/AspectElementFactory.java @@ -11,7 +11,7 @@ public class AspectElementFactory { throw new IllegalStateException("Utility class"); } - public static JastAddAspectAstTypeName createComponentName(Project project, String name) { + public static JastAddAspectAstTypeName createAstTypeName(Project project, String name) { final AspectFile file = createFile(project, "aspect A{syn int " + name + ".attributeName();}"); PsiElement result = file.getFirstChild().findElementAt(17); if (result != null) { @@ -20,6 +20,15 @@ public class AspectElementFactory { return null; } + public static JastAddAspectClassOrInterfaceType createClassOrInterfaceType(Project project, String name) { + final AspectFile file = createFile(project, "aspect Navigation{X<" + name + "> X.z=0;}"); + PsiElement result = file.getFirstChild().findElementAt(20); + if (result != null) { + return (JastAddAspectClassOrInterfaceType) result.getParent().getParent(); + } + return null; + } + public static AspectFile createFile(Project project, String text) { String name = "dummy.jrag"; return (AspectFile) PsiFileFactory.getInstance(project). diff --git a/src/main/java/org/jastadd/tooling/aspect/psi/JastAddAspectClassOrInterfaceTypeManipulator.java b/src/main/java/org/jastadd/tooling/aspect/psi/JastAddAspectClassOrInterfaceTypeManipulator.java new file mode 100644 index 0000000000000000000000000000000000000000..88e3f360e2130909052ce4aad975a7ab6da95eb9 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/psi/JastAddAspectClassOrInterfaceTypeManipulator.java @@ -0,0 +1,32 @@ +package org.jastadd.tooling.aspect.psi; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.AbstractElementManipulator; +import com.intellij.psi.ElementManipulator; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class JastAddAspectClassOrInterfaceTypeManipulator extends AbstractElementManipulator<JastAddAspectClassOrInterfaceType> implements ElementManipulator<JastAddAspectClassOrInterfaceType> { + /** + * Changes the element's text to the given new text. + * + * @param element element to be changed + * @param range range within the element + * @param newContent new element text + * @return changed element + * @throws IncorrectOperationException if something goes wrong + */ + @Nullable + @Override + public JastAddAspectClassOrInterfaceType handleContentChange(@NotNull JastAddAspectClassOrInterfaceType element, @NotNull TextRange range, String newContent) { + try { + if (element.getJavaIdentifierList().size() != 1 || !element.getTypeArgumentsList().isEmpty()) { + throw new IncorrectOperationException("Operation only valid for \"primitive\" instances of JastAddAspectClassOrInterfaceType"); + } + return (JastAddAspectClassOrInterfaceType) element.setName(range.replace(element.getText(), newContent)); + } catch (Exception e) { // e.g., in case the range is wrong + throw new IncorrectOperationException(e); + } + } +} diff --git a/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectAstTypeNameImplExtension.java b/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectAstTypeNameImplExtension.java index f4917a4f618de5c893c76f477f559b2aa698ccc3..a362105f8536969966718982ad9f88c553b89b92 100644 --- a/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectAstTypeNameImplExtension.java +++ b/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectAstTypeNameImplExtension.java @@ -4,9 +4,7 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jastadd.tooling.aspect.psi.AspectElementFactory; import org.jastadd.tooling.aspect.psi.JastAddAspectAstTypeName; -import org.jastadd.tooling.grammar.psi.GrammarElementFactory; import org.jastadd.tooling.grammar.psi.GrammarNamedElement; -import org.jastadd.tooling.grammar.psi.GrammarTypeName; import org.jastadd.tooling.grammar.psi.impl.GrammarNamedElementImpl; import org.jetbrains.annotations.NotNull; @@ -25,7 +23,7 @@ public class JastAddAspectAstTypeNameImplExtension extends GrammarNamedElementIm // 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) { - JastAddAspectAstTypeName name = AspectElementFactory.createComponentName(getProject(), newName); + JastAddAspectAstTypeName name = AspectElementFactory.createAstTypeName(getProject(), newName); ASTNode newKeyNode = name.getNode().getFirstChildNode(); getNode().replaceChild(keyNode, newKeyNode); } diff --git a/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectClassOrInterfaceTypeImplExtension.java b/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectClassOrInterfaceTypeImplExtension.java new file mode 100644 index 0000000000000000000000000000000000000000..26927ffe375806d4f892a885596842db8665395e --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectClassOrInterfaceTypeImplExtension.java @@ -0,0 +1,37 @@ +package org.jastadd.tooling.aspect.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import org.jastadd.tooling.aspect.psi.AspectElementFactory; +import org.jastadd.tooling.aspect.psi.JastAddAspectClassOrInterfaceType; +import org.jastadd.tooling.grammar.psi.GrammarNamedElement; +import org.jastadd.tooling.grammar.psi.impl.GrammarNamedElementImpl; +import org.jetbrains.annotations.NotNull; + +public class JastAddAspectClassOrInterfaceTypeImplExtension extends GrammarNamedElementImpl implements GrammarNamedElement { + + public JastAddAspectClassOrInterfaceTypeImplExtension(@NotNull ASTNode node) { + super(node); + } + + public String getName() { + // this finds the *first* ID, which is what we want + return getNode().getText(); + } + + 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) { + JastAddAspectClassOrInterfaceType name = AspectElementFactory.createClassOrInterfaceType(getProject(), newName); + ASTNode newKeyNode = name.getNode().getFirstChildNode(); + getNode().replaceChild(keyNode, newKeyNode); + } + return this; + } + + public PsiElement getNameIdentifier() { + return getNode().getPsi(); + } + +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index b4dc17d7dcb91bbe10030d6d062ebe44004c7932..01ee6c38d725034ee421dca47285c63dcf311649 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -84,6 +84,9 @@ <lang.elementManipulator forClass="org.jastadd.tooling.aspect.psi.JastAddAspectAstTypeName" implementationClass="org.jastadd.tooling.aspect.psi.JastAddAspectAstTypeNameManipulator"/> + + <lang.elementManipulator forClass="org.jastadd.tooling.aspect.psi.JastAddAspectClassOrInterfaceType" + implementationClass="org.jastadd.tooling.aspect.psi.JastAddAspectClassOrInterfaceTypeManipulator"/> </extensions> <actions>