From 1137b28b1e47b584fa5f8aab6393d84c68e9a94e Mon Sep 17 00:00:00 2001 From: Johannes Mey <johannes.mey@tu-dresden.de> Date: Mon, 22 Nov 2021 00:23:38 +0100 Subject: [PATCH] renaming also works in aspect files (outside injected java) --- src/main/grammar/Aspect.bnf | 38 ++++++++++-------- .../aspect/AspectReferenceContributor.java | 32 +++++++++++++++ .../aspect/psi/AspectElementFactory.java | 28 +++++++++++++ .../JastAddAspectAstTypeNameManipulator.java | 29 ++++++++++++++ ...JastAddAspectAstTypeNameImplExtension.java | 39 +++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 5 +++ 6 files changed, 155 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java create mode 100644 src/main/java/org/jastadd/tooling/aspect/psi/AspectElementFactory.java create mode 100644 src/main/java/org/jastadd/tooling/aspect/psi/JastAddAspectAstTypeNameManipulator.java create mode 100644 src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectAstTypeNameImplExtension.java diff --git a/src/main/grammar/Aspect.bnf b/src/main/grammar/Aspect.bnf index c2ada4a..f112d4c 100644 --- a/src/main/grammar/Aspect.bnf +++ b/src/main/grammar/Aspect.bnf @@ -101,50 +101,50 @@ aspect_nested_interface_declaration ::= modifiers interface_declaration // TODO check if simplification is okay aspect_nested_class_declaration ::= modifiers class_declaration -aspect_method_declaration ::= modifiers type_parameters? aspect_result_type IDENTIFIER DOT method_declarator (THROWS name_list)? (block | SEMICOLON) +aspect_method_declaration ::= modifiers type_parameters? aspect_result_type ast_type_name DOT method_declarator (THROWS name_list)? (block | SEMICOLON) aspect_refine_method_declaration ::= REFINE [IDENTIFIER] modifiers type_parameters? aspect_result_type IDENTIFIER DOT method_declarator (THROWS name_list)? (block | SEMICOLON) -aspect_constructor_declaration ::= modifiers IDENTIFIER DOT IDENTIFIER formal_parameters (THROWS name_list)? LBRACE explicit_constructor_invocation? block_statement* RBRACE +aspect_constructor_declaration ::= modifiers ast_type_name DOT ast_type_name formal_parameters (THROWS name_list)? LBRACE explicit_constructor_invocation? block_statement* RBRACE -aspect_refine_constructor_declaration ::= REFINE IDENTIFIER (PUBLIC | PROTECTED | PRIVATE) IDENTIFIER DOT IDENTIFIER formal_parameters (THROWS name_list)? LBRACE block_statement* RBRACE +aspect_refine_constructor_declaration ::= REFINE IDENTIFIER (PUBLIC | PROTECTED | PRIVATE) ast_type_name DOT IDENTIFIER formal_parameters (THROWS name_list)? LBRACE block_statement* RBRACE -aspect_field_declaration ::= modifiers aspect_type IDENTIFIER DOT variable_declarator (COMMA variable_declarator)* SEMICOLON +aspect_field_declaration ::= modifiers aspect_type ast_type_name DOT variable_declarator (COMMA variable_declarator)* SEMICOLON -aspect_syn_attribute_declaration ::= annotation* SYN NTA? LAZY? FINAL? aspect_type IDENTIFIER DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)* )? RPAREN (CIRCULAR LBRACKET expression RBRACKET)? ( ASSIGN expression SEMICOLON | block | SEMICOLON ) +aspect_syn_attribute_declaration ::= annotation* SYN NTA? LAZY? FINAL? aspect_type ast_type_name DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)* )? RPAREN (CIRCULAR LBRACKET expression RBRACKET)? ( ASSIGN expression SEMICOLON | block | SEMICOLON ) { implements="org.jastadd.tooling.aspect.psi.JastAddAspectAttribute" extends="org.jastadd.tooling.aspect.psi.impl.JastAddAspectSynAttributeImpl" } -aspect_inh_attribute_declaration ::= annotation* INH NTA? LAZY? FINAL? aspect_type IDENTIFIER DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)* )? RPAREN (CIRCULAR LBRACKET expression RBRACKET)? SEMICOLON +aspect_inh_attribute_declaration ::= annotation* INH NTA? LAZY? FINAL? aspect_type ast_type_name DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)* )? RPAREN (CIRCULAR LBRACKET expression RBRACKET)? SEMICOLON { implements="org.jastadd.tooling.aspect.psi.JastAddAspectAttribute" extends="org.jastadd.tooling.aspect.psi.impl.JastAddAspectInhAttributeImpl" } // FIXME parentheses are not required around the WHEN expression? -aspect_rewrite ::= REWRITE IDENTIFIER (IDENTIFIER DOT IDENTIFIER LPAREN RPAREN)? LBRACE ((WHEN LPAREN expression RPAREN)? TO aspect_type ( expression SEMICOLON | block ))+ RBRACE +aspect_rewrite ::= REWRITE IDENTIFIER (ast_type_name DOT IDENTIFIER LPAREN RPAREN)? LBRACE ((WHEN LPAREN expression RPAREN)? TO aspect_type ( expression SEMICOLON | block ))+ RBRACE -aspect_syn_equation ::= annotation* EQUATION IDENTIFIER DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN ( ASSIGN expression SEMICOLON | block ) +aspect_syn_equation ::= annotation* EQUATION ast_type_name DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN ( ASSIGN expression SEMICOLON | block ) -aspect_refine_syn_equation ::= REFINE IDENTIFIER EQUATION IDENTIFIER DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN (ASSIGN expression SEMICOLON | block) +aspect_refine_syn_equation ::= REFINE IDENTIFIER EQUATION ast_type_name DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN (ASSIGN expression SEMICOLON | block) -aspect_inh_equation ::= annotation* EQUATION IDENTIFIER DOT IDENTIFIER LPAREN (INT IDENTIFIER)? RPAREN DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN (ASSIGN expression SEMICOLON | block) +aspect_inh_equation ::= annotation* EQUATION ast_type_name DOT IDENTIFIER LPAREN (INT IDENTIFIER)? RPAREN DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN (ASSIGN expression SEMICOLON | block) -aspect_refine_inh_equation ::= REFINE IDENTIFIER EQUATION IDENTIFIER DOT IDENTIFIER LPAREN (INT IDENTIFIER)? RPAREN DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN (ASSIGN expression SEMICOLON | block) +aspect_refine_inh_equation ::= REFINE IDENTIFIER EQUATION ast_type_name DOT IDENTIFIER LPAREN (INT IDENTIFIER)? RPAREN DOT attribute_name LPAREN (type IDENTIFIER (COMMA type IDENTIFIER)*)? RPAREN (ASSIGN expression SEMICOLON | block) -collection_attribute ::= annotation* COLL aspect_type IDENTIFIER DOT attribute_name LPAREN RPAREN CIRCULAR? (LBRACKET expression RBRACKET)? (WITH IDENTIFIER)? (ROOT IDENTIFIER)? SEMICOLON +collection_attribute ::= annotation* COLL aspect_type ast_type_name DOT attribute_name LPAREN RPAREN CIRCULAR? (LBRACKET expression RBRACKET)? (WITH IDENTIFIER)? (ROOT IDENTIFIER)? SEMICOLON { implements="org.jastadd.tooling.aspect.psi.JastAddAspectAttribute" extends="org.jastadd.tooling.aspect.psi.impl.JastAddAspectCollAttributeImpl" } -collection_contribution ::= annotation* IDENTIFIER CONTRIBUTES ( NTA expression TO IDENTIFIER DOT attribute_name LPAREN RPAREN | EACH? expression (WHEN expression)? TO IDENTIFIER DOT attribute_name LPAREN RPAREN (FOR EACH? expression)? | block TO IDENTIFIER DOT attribute_name LPAREN RPAREN ) SEMICOLON +collection_contribution ::= annotation* ast_type_name CONTRIBUTES ( NTA expression TO ast_type_name DOT attribute_name LPAREN RPAREN | EACH? expression (WHEN expression)? TO ast_type_name DOT attribute_name LPAREN RPAREN (FOR EACH? expression)? | block TO ast_type_name DOT attribute_name LPAREN RPAREN ) SEMICOLON -aspect_add_interface ::= IDENTIFIER IMPLEMENTS type_name_list SEMICOLON +aspect_add_interface ::= ast_type_name IMPLEMENTS type_name_list SEMICOLON -aspect_extend_interface ::= IDENTIFIER EXTENDS type_name_list SEMICOLON +aspect_extend_interface ::= ast_type_name EXTENDS type_name_list SEMICOLON class_declaration ::= CLASS IDENTIFIER type_parameters? (EXTENDS class_or_interface_type)? (implements type_name_list)? class_body @@ -208,7 +208,7 @@ aspect_result_type ::= VOID | aspect_type aspect_reference_type ::= aspect_class_or_interface_type (LBRACKET RBRACKET)* -aspect_class_or_interface_type ::= IDENTIFIER type_arguments? (DOT java_identifier type_arguments? )* +aspect_class_or_interface_type ::= ast_type_name type_arguments? (DOT java_identifier type_arguments? )* type ::= reference_type | primitive_type @@ -386,5 +386,11 @@ java_identifier ::= IDENTIFIER | INH | SYN | LAZY | REWRITE | TO | WHEN | ASPECT attribute_name ::= IDENTIFIER +ast_type_name ::= IDENTIFIER +{ + extends="org.jastadd.tooling.aspect.psi.impl.JastAddAspectAstTypeNameImplExtension" + implements="org.jastadd.tooling.grammar.psi.GrammarNamedElement" +} + // unused keywords must still appear somewhere unused_keywords ::= GOTO | CONST ELLIPSIS | PACKAGE diff --git a/src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java b/src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java new file mode 100644 index 0000000..139081c --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/AspectReferenceContributor.java @@ -0,0 +1,32 @@ +package org.jastadd.tooling.aspect; + +import com.intellij.openapi.util.TextRange; +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.grammar.GrammarReference; +import org.jetbrains.annotations.NotNull; + +public class AspectReferenceContributor extends PsiReferenceContributor { + + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider(PlatformPatterns.psiElement(JastAddAspectAstTypeName.class), + new PsiReferenceProvider() { + @NotNull + @Override + public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement element, + @NotNull ProcessingContext context) { + JastAddAspectAstTypeName typeReference = (JastAddAspectAstTypeName) element; + String value = typeReference.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 new file mode 100644 index 0000000..aa40835 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/psi/AspectElementFactory.java @@ -0,0 +1,28 @@ +package org.jastadd.tooling.aspect.psi; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFileFactory; +import org.jastadd.tooling.aspect.AspectFileType; + +public class AspectElementFactory { + + private AspectElementFactory() { + throw new IllegalStateException("Utility class"); + } + + public static JastAddAspectAstTypeName createComponentName(Project project, String name) { + final AspectFile file = createFile(project, "aspect A{syn int " + name + ".attributeName();}"); + PsiElement result = file.getFirstChild().findElementAt(17); + if (result != null) { + return (JastAddAspectAstTypeName) result.getParent(); + } + return null; + } + + public static AspectFile createFile(Project project, String text) { + String name = "dummy.jrag"; + return (AspectFile) PsiFileFactory.getInstance(project). + createFileFromText(name, AspectFileType.INSTANCE, text); + } +} diff --git a/src/main/java/org/jastadd/tooling/aspect/psi/JastAddAspectAstTypeNameManipulator.java b/src/main/java/org/jastadd/tooling/aspect/psi/JastAddAspectAstTypeNameManipulator.java new file mode 100644 index 0000000..894ddf8 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/psi/JastAddAspectAstTypeNameManipulator.java @@ -0,0 +1,29 @@ +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 JastAddAspectAstTypeNameManipulator extends AbstractElementManipulator<JastAddAspectAstTypeName> implements ElementManipulator<JastAddAspectAstTypeName> { + /** + * 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 JastAddAspectAstTypeName handleContentChange(@NotNull JastAddAspectAstTypeName element, @NotNull TextRange range, String newContent) { + try { + return (JastAddAspectAstTypeName) 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 new file mode 100644 index 0000000..f4917a4 --- /dev/null +++ b/src/main/java/org/jastadd/tooling/aspect/psi/impl/JastAddAspectAstTypeNameImplExtension.java @@ -0,0 +1,39 @@ +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.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; + +public class JastAddAspectAstTypeNameImplExtension extends GrammarNamedElementImpl implements GrammarNamedElement { + + public JastAddAspectAstTypeNameImplExtension(@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) { + JastAddAspectAstTypeName name = AspectElementFactory.createComponentName(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 c5bdfc6..b4dc17d 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -79,6 +79,11 @@ <annotator language="JAVA" implementationClass="org.jastadd.tooling.java.JavaMethodHighlighter"/> <colorSettingsPage implementation="org.jastadd.tooling.java.JavaColorSettingsPage"/> + + <psi.referenceContributor implementation="org.jastadd.tooling.aspect.AspectReferenceContributor"/> + + <lang.elementManipulator forClass="org.jastadd.tooling.aspect.psi.JastAddAspectAstTypeName" + implementationClass="org.jastadd.tooling.aspect.psi.JastAddAspectAstTypeNameManipulator"/> </extensions> <actions> -- GitLab