From 0023a469e2c54d551c9df6ece9b80e88481e99e2 Mon Sep 17 00:00:00 2001
From: Johannes Mey <johannes.mey@tu-dresden.de>
Date: Sun, 21 Nov 2021 21:22:22 +0100
Subject: [PATCH] distinguish name and refernce

---
 src/main/grammar/Grammar.bnf                  | 16 ++++++--
 .../tooling/grammar/GrammarAnnotator.java     |  6 +--
 .../GrammarChooseByNameContributor.java       |  2 +-
 .../GrammarRefactoringSupportProvider.java    |  4 +-
 .../tooling/grammar/GrammarReference.java     |  2 +-
 ...rammarRemoveRedundantComponentNameFix.java |  4 +-
 .../grammar/psi/GrammarElementFactory.java    |  9 ++++-
 .../GrammarComponentNameImplExtension.java    | 37 +++++++++++++++++++
 .../impl/GrammarTypeDeclImplExtension.java    | 10 ++---
 .../impl/GrammarTypeNameImplExtension.java    | 36 ++++++++++++++++++
 10 files changed, 106 insertions(+), 20 deletions(-)
 create mode 100644 src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarComponentNameImplExtension.java
 create mode 100644 src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeNameImplExtension.java

diff --git a/src/main/grammar/Grammar.bnf b/src/main/grammar/Grammar.bnf
index d5165bd..ca92e0f 100644
--- a/src/main/grammar/Grammar.bnf
+++ b/src/main/grammar/Grammar.bnf
@@ -19,7 +19,7 @@ GrammarFile ::= comment* ((type_decl | relation) comment*)*
 
 comment ::= (WHITESPACE | MULTILINECOMMENT | DOCCOMMENT | SINGLELINECOMMENT)
 
-type_decl ::= ABSTRACT? declared_name (COL type_reference)? (ASSIGN (component | nta_component)*)? SCOL
+type_decl ::= ABSTRACT? type_name (COL type_reference)? (ASSIGN (component | nta_component)*)? SCOL
 {
   extends="org.jastadd.tooling.grammar.psi.impl.GrammarTypeDeclImplExtension"
   implements="org.jastadd.tooling.grammar.psi.GrammarNamedElement"
@@ -27,7 +27,7 @@ type_decl ::= ABSTRACT? declared_name (COL type_reference)? (ASSIGN (component |
 
 nta_component ::= SLASH component SLASH
 
-component ::= (declared_name COL type_reference STAR?) | (type_reference STAR?) | (LBRACKET declared_name COL type_reference RBRACKET) | (LBRACKET type_reference RBRACKET) | (LT declared_name (COL (java_type_use))? GT)
+component ::= (component_name COL type_reference STAR?) | (type_reference STAR?) | (LBRACKET component_name COL type_reference RBRACKET) | (LBRACKET type_reference RBRACKET) | (LT component_name (COL (java_type_use))? GT)
 
 java_type_use ::=  parameterized_java_type_use | simple_java_type_use
 
@@ -39,14 +39,22 @@ relation ::=  REL ((unnamed_role LEFT navigable_role) | (navigable_role RIGHT un
 
 unnamed_role ::= type_reference | navigable_role
 
-navigable_role ::= type_reference DOT declared_name (STAR | QUESTION_MARK)?
+navigable_role ::= type_reference DOT component_name (STAR | QUESTION_MARK)?
 
 // for auto-completion, it is helpful if we can distinguish the different IDs
-declared_name ::= ID
+type_name ::= ID
+
 type_reference ::= ID
 {
   extends="org.jastadd.tooling.grammar.psi.impl.GrammarTypeReferenceImplExtension"
   implements="org.jastadd.tooling.grammar.psi.GrammarNamedElement"
 }
 
+component_name ::= ID
+{
+  extends="org.jastadd.tooling.grammar.psi.impl.GrammarComponentNameImplExtension"
+  implements="org.jastadd.tooling.grammar.psi.GrammarNamedElement"
+}
+
+
 java_name ::= ID
diff --git a/src/main/java/org/jastadd/tooling/grammar/GrammarAnnotator.java b/src/main/java/org/jastadd/tooling/grammar/GrammarAnnotator.java
index 6797345..7e50155 100644
--- a/src/main/java/org/jastadd/tooling/grammar/GrammarAnnotator.java
+++ b/src/main/java/org/jastadd/tooling/grammar/GrammarAnnotator.java
@@ -18,11 +18,11 @@ public class GrammarAnnotator implements Annotator {
 
     if (element instanceof GrammarComponent) {
       GrammarComponent component = (GrammarComponent) element;
-      if (component.getTypeReference() != null && component.getDeclaredName() != null) {
-        String name = component.getDeclaredName().getText();
+      if (component.getTypeReference() != null && component.getComponentName() != null) {
+        String name = component.getComponentName().getText();
         if (name != null && !name.equals("") && name.equals(component.getTypeReference().getName())) {
           holder.newAnnotation(HighlightSeverity.WEAK_WARNING, "Redundant name")
-            .range(component.getDeclaredName().getTextRange())
+            .range(component.getComponentName().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.")
diff --git a/src/main/java/org/jastadd/tooling/grammar/GrammarChooseByNameContributor.java b/src/main/java/org/jastadd/tooling/grammar/GrammarChooseByNameContributor.java
index f1d88f5..615f51e 100644
--- a/src/main/java/org/jastadd/tooling/grammar/GrammarChooseByNameContributor.java
+++ b/src/main/java/org/jastadd/tooling/grammar/GrammarChooseByNameContributor.java
@@ -18,7 +18,7 @@ public class GrammarChooseByNameContributor implements ChooseByNameContributor {
     List<GrammarTypeDecl> typeDecls = GrammarUtil.findTypeDecl(project);
     List<String> names = new ArrayList<>(typeDecls.size());
     for (GrammarTypeDecl typeDecl : typeDecls) {
-      if (typeDecl.getName() != null && typeDecl.getName().length() > 0) {
+      if (typeDecl.getName() != null && !typeDecl.getName().isEmpty()) {
         names.add(typeDecl.getName());
       }
     }
diff --git a/src/main/java/org/jastadd/tooling/grammar/GrammarRefactoringSupportProvider.java b/src/main/java/org/jastadd/tooling/grammar/GrammarRefactoringSupportProvider.java
index 1e70ce5..c726f79 100644
--- a/src/main/java/org/jastadd/tooling/grammar/GrammarRefactoringSupportProvider.java
+++ b/src/main/java/org/jastadd/tooling/grammar/GrammarRefactoringSupportProvider.java
@@ -3,7 +3,7 @@ package org.jastadd.tooling.grammar;
 
 import com.intellij.lang.refactoring.RefactoringSupportProvider;
 import com.intellij.psi.PsiElement;
-import org.jastadd.tooling.grammar.psi.GrammarDeclaredName;
+import org.jastadd.tooling.grammar.psi.GrammarTypeName;
 import org.jastadd.tooling.grammar.psi.GrammarTypeReference;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -14,7 +14,7 @@ public class GrammarRefactoringSupportProvider extends RefactoringSupportProvide
   public boolean isMemberInplaceRenameAvailable(@NotNull PsiElement elementToRename, @Nullable PsiElement context) {
     // in-place rename is still not available since not all requirements are met
     // see https://intellij-support.jetbrains.com/hc/en-us/community/posts/360006918740-How-do-I-enable-in-place-rename-Renaming-via-dialog-works-fine-
-    return (elementToRename instanceof GrammarDeclaredName) || (elementToRename instanceof GrammarTypeReference);
+    return (elementToRename instanceof GrammarTypeName) || (elementToRename instanceof GrammarTypeReference);
   }
 
 }
diff --git a/src/main/java/org/jastadd/tooling/grammar/GrammarReference.java b/src/main/java/org/jastadd/tooling/grammar/GrammarReference.java
index 3c6fc4b..2825e66 100644
--- a/src/main/java/org/jastadd/tooling/grammar/GrammarReference.java
+++ b/src/main/java/org/jastadd/tooling/grammar/GrammarReference.java
@@ -48,7 +48,7 @@ public class GrammarReference extends PsiReferenceBase<PsiElement> implements Ps
     List<GrammarTypeDecl> typeDecls = GrammarUtil.findTypeDecl(project);
     List<LookupElement> variants = new ArrayList<>();
     for (final GrammarTypeDecl typeDecl : typeDecls) {
-      if (typeDecl.getName() != null && typeDecl.getName().length() > 0) {
+      if (typeDecl.getName() != null && !typeDecl.getName().isEmpty()) {
         variants.add(LookupElementBuilder
           .create(typeDecl).withIcon(JastAddIcons.FILE)
           .withPresentableText(typeDecl.getName())
diff --git a/src/main/java/org/jastadd/tooling/grammar/GrammarRemoveRedundantComponentNameFix.java b/src/main/java/org/jastadd/tooling/grammar/GrammarRemoveRedundantComponentNameFix.java
index b906a76..a95cb2a 100644
--- a/src/main/java/org/jastadd/tooling/grammar/GrammarRemoveRedundantComponentNameFix.java
+++ b/src/main/java/org/jastadd/tooling/grammar/GrammarRemoveRedundantComponentNameFix.java
@@ -38,8 +38,8 @@ public class GrammarRemoveRedundantComponentNameFix extends BaseIntentionAction
   @Override
   public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws
     IncorrectOperationException {
-    PsiElement first = component.getDeclaredName();
-    PsiElement last = component.getDeclaredName();
+    PsiElement first = component.getComponentName();
+    PsiElement last = component.getComponentName();
     while (last != null && last.getNode().getElementType() != GrammarTypes.COL) {
       last = last.getNextSibling();
     }
diff --git a/src/main/java/org/jastadd/tooling/grammar/psi/GrammarElementFactory.java b/src/main/java/org/jastadd/tooling/grammar/psi/GrammarElementFactory.java
index 05a33fa..aaacf26 100644
--- a/src/main/java/org/jastadd/tooling/grammar/psi/GrammarElementFactory.java
+++ b/src/main/java/org/jastadd/tooling/grammar/psi/GrammarElementFactory.java
@@ -13,9 +13,9 @@ public class GrammarElementFactory {
     throw new IllegalStateException("Utility class");
   }
 
-  public static GrammarDeclaredName createDeclaredName(Project project, String name) {
+  public static GrammarTypeName createTypeName(Project project, String name) {
     final GrammarFile file = createFile(project, name + ";");
-    return (GrammarDeclaredName) file.getFirstChild().getFirstChild();
+    return (GrammarTypeName) file.getFirstChild().getFirstChild();
   }
 
   public static GrammarTypeReference createTypeReference(Project project, String name) {
@@ -23,6 +23,11 @@ public class GrammarElementFactory {
     return (GrammarTypeReference) (Objects.requireNonNull(file.getFirstChild().getNode().findChildByType(GrammarTypes.TYPE_REFERENCE)).getPsi());
   }
 
+  public static GrammarComponentName createComponentName(Project project, String name) {
+    final GrammarFile file = createFile(project, "X ::= " + name + ":X ;");
+    return (GrammarComponentName) file.getFirstChild().getFirstChild();
+  }
+
   public static GrammarFile createFile(Project project, String text) {
     String name = "dummy.relast";
     return (GrammarFile) PsiFileFactory.getInstance(project).
diff --git a/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarComponentNameImplExtension.java b/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarComponentNameImplExtension.java
new file mode 100644
index 0000000..84e04ad
--- /dev/null
+++ b/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarComponentNameImplExtension.java
@@ -0,0 +1,37 @@
+package org.jastadd.tooling.grammar.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import org.jastadd.tooling.grammar.psi.GrammarComponentName;
+import org.jastadd.tooling.grammar.psi.GrammarElementFactory;
+import org.jastadd.tooling.grammar.psi.GrammarNamedElement;
+import org.jastadd.tooling.grammar.psi.GrammarTypeReference;
+import org.jetbrains.annotations.NotNull;
+
+public class GrammarComponentNameImplExtension extends GrammarNamedElementImpl implements GrammarNamedElement {
+
+  public GrammarComponentNameImplExtension(@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) {
+      GrammarComponentName name = GrammarElementFactory.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/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeDeclImplExtension.java b/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeDeclImplExtension.java
index 8634701..39bd24d 100644
--- a/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeDeclImplExtension.java
+++ b/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeDeclImplExtension.java
@@ -3,9 +3,9 @@ package org.jastadd.tooling.grammar.psi.impl;
 import com.intellij.lang.ASTNode;
 import com.intellij.psi.PsiElement;
 import org.jastadd.tooling.grammar.parser.GrammarTypes;
-import org.jastadd.tooling.grammar.psi.GrammarDeclaredName;
 import org.jastadd.tooling.grammar.psi.GrammarElementFactory;
 import org.jastadd.tooling.grammar.psi.GrammarNamedElement;
+import org.jastadd.tooling.grammar.psi.GrammarTypeName;
 import org.jetbrains.annotations.NotNull;
 
 public class GrammarTypeDeclImplExtension extends GrammarNamedElementImpl implements GrammarNamedElement {
@@ -16,7 +16,7 @@ public class GrammarTypeDeclImplExtension extends GrammarNamedElementImpl implem
 
   public String getName() {
     // this finds the *first* ID, which is what we want
-    ASTNode keyNode = getNode().findChildByType(GrammarTypes.DECLARED_NAME);
+    ASTNode keyNode = getNode().findChildByType(GrammarTypes.TYPE_NAME);
     if (keyNode != null) {
       return keyNode.getText();
     } else {
@@ -25,9 +25,9 @@ public class GrammarTypeDeclImplExtension extends GrammarNamedElementImpl implem
   }
 
   public PsiElement setName(@NotNull String newName) {
-    ASTNode keyNode = getNode().findChildByType(GrammarTypes.DECLARED_NAME);
+    ASTNode keyNode = getNode().findChildByType(GrammarTypes.TYPE_NAME);
     if (keyNode != null) {
-      GrammarDeclaredName name = GrammarElementFactory.createDeclaredName(getProject(), newName);
+      GrammarTypeName name = GrammarElementFactory.createTypeName(getProject(), newName);
       ASTNode newKeyNode = name.getNode();
       getNode().replaceChild(keyNode, newKeyNode);
     }
@@ -35,7 +35,7 @@ public class GrammarTypeDeclImplExtension extends GrammarNamedElementImpl implem
   }
 
   public PsiElement getNameIdentifier() {
-    ASTNode keyNode = getNode().findChildByType(GrammarTypes.DECLARED_NAME);
+    ASTNode keyNode = getNode().findChildByType(GrammarTypes.TYPE_NAME);
     if (keyNode != null) {
       return keyNode.getPsi();
     } else {
diff --git a/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeNameImplExtension.java b/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeNameImplExtension.java
new file mode 100644
index 0000000..753e63c
--- /dev/null
+++ b/src/main/java/org/jastadd/tooling/grammar/psi/impl/GrammarTypeNameImplExtension.java
@@ -0,0 +1,36 @@
+package org.jastadd.tooling.grammar.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import org.jastadd.tooling.grammar.psi.GrammarElementFactory;
+import org.jastadd.tooling.grammar.psi.GrammarNamedElement;
+import org.jastadd.tooling.grammar.psi.GrammarTypeName;
+import org.jetbrains.annotations.NotNull;
+
+public class GrammarTypeNameImplExtension extends GrammarNamedElementImpl implements GrammarNamedElement {
+
+  public GrammarTypeNameImplExtension(@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) {
+      GrammarTypeName name = GrammarElementFactory.createTypeName(getProject(), newName);
+      ASTNode newKeyNode = name.getNode().getFirstChildNode();
+      getNode().replaceChild(keyNode, newKeyNode);
+    }
+    return this;
+  }
+
+  public PsiElement getNameIdentifier() {
+    return getNode().getPsi();
+  }
+
+}
-- 
GitLab