2020-02-10 09:40:22 -08:00

5.8 KiB

title
10. Reference Contributor

The References functionality is one of the most important parts in the implementation of custom language support. Resolving references means the ability to go from the usage of an element to its declaration, completion, rename refactoring, find usages, etc.

Note

Every PSI element that can be renamed or referenced needs to implement PsiNamedElement interface.

  • bullet list {:toc}

10.1. Define a Named Element Class

The simplified class diagram below shows how the Simple language fulfills the need to implement PsiNamedElement. The SimpleNamedElement interface is subclassed from PsiNameIdentifierOwner. The SimpleNamedElementImpl class implements the SimpleNamedElement interface and extends ASTWrapperPsiElement.

SimpleNamedElementImpl class hierarchy{:width="400px"}

10.2. Define Helper Methods for Generated PSI Elements

Modify SimplePsiImplUtil to support new methods that will get added to the PSI class for Simple language. Note that SimpleElementFactory isn't defined until the next step, so for now it shows as an error.

public class SimplePsiImplUtil {

  // ...

  public static String getName(SimpleProperty element) {
      return getKey(element);
  }

  public static PsiElement setName(SimpleProperty element, String newName) {
      ASTNode keyNode = element.getNode().findChildByType(SimpleTypes.KEY);
      if (keyNode != null) {

          SimpleProperty property = SimpleElementFactory.createProperty(element.getProject(), newName);
          ASTNode newKeyNode = property.getFirstChild().getNode();
          element.getNode().replaceChild(keyNode, newKeyNode);
      }
      return element;
  }

  public static PsiElement getNameIdentifier(SimpleProperty element) {
      ASTNode keyNode = element.getNode().findChildByType(SimpleTypes.KEY);
      if (keyNode != null) {
          return keyNode.getPsi();
      } else {
          return null;
      }
  }

  // ...
}

10.3. Define an Element Factory

The SimpleElementFactory provides methods for creating SimpleFile.

{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementFactory.java %}

10.4. Update Grammar and Regenerate the Parser

Now make corresponding changes to the Simple.bnf grammar file by replacing the property definition with the line below. Don't forget to regenerate the parser after updating the file! Right click on the Simple.bnf file and select Generate Parser Code.

property ::= (KEY? SEPARATOR VALUE?) | KEY {mixin="com.intellij.sdk.language.psi.impl.SimpleNamedElementImpl"
  implements="com.intellij.sdk.language.psi.SimpleNamedElement" methods=[getKey getValue getName setName getNameIdentifier]}

10.5. Define a Reference

Now define a reference class to resolve a property from its usage.

{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleReference.java %}

10.6. Define a Reference Contributor

A reference contributor allows the simple_language plugin to provide references to Simple language from elements in other languages such as Java. Create SimpleReferenceContributor by subclassing PsiReferenceContributor. Contribute a reference to each usage of a property:

{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleReferenceContributor.java %}

10.7. Register the Reference Contributor

The SimpleReferenceContributor implementation is registered with the IntelliJ Platform using the psi.referenceContributor extension point.

  <extensions defaultExtensionNs="com.intellij">
    <psi.referenceContributor implementation="com.intellij.sdk.language.SimpleReferenceContributor"/>
  </extensions>

10.8. Run the Project

Rebuild the project, and run simple_language in a Development Instance. The IDE now resolves the property and provides completion suggestions:

Reference Contributor{:width="800px"}

The Rename refactoring functionality is now available from definition and usages.

Rename{:width="800px"}

10.9. Define a Refactoring Support Provider

To allow in-place refactoring it is specified explicitly in a refactoring support provider. Create SimpleRefactoringSupportProvider by subclassing RefactoringSupportProvider As long as an element is a SimpleProperty it is allowed to be refactored:

{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleRefactoringSupportProvider.java %}

10.10. Register the Refactoring Support Provider

The SimpleRefactoringSupportProvider implementation is registered with the IntelliJ Platform using the lang.refactoringSupport extension point.

  <extensions defaultExtensionNs="com.intellij">
    <lang.refactoringSupport language="Simple" implementationClass="com.intellij.sdk.language.SimpleRefactoringSupportProvider"/>
  </extensions>

10.11. Run the Project

Rebuild the project, and run simple_language in a Development Instance. The IDE now supports refactoring suggestions:

In Place Rename{:width="800px"}