PSI Reference Help with Salesforce APEX Plugin

I'm running into issues with PSI references for my Salesforce plugin.  I've followed the tutorial here: http://confluence.jetbrains.com/display/IntelliJIDEA/Custom+Language+Support.  And created a basic project here: https://github.com/polyglot-mark/apex-plugin.

Note: I've skipped the Syntax Highlighter and Color Settings Page and Line Marker steps for now.   I just wanted to get the PSI references working.

I've gotten Annotations working.  I sort of have a Completions Contributor working.  But I'm stuck on Reference Contributor.

I've been through all the forum posts and discovered that I needed to add the following to my abstract "base named element" class:

public abstract class ApexNamedElementImpl extends ASTWrapperPsiElement implements ApexNamedElement  {

    public ApexNamedElementImpl(@NotNull ASTNode node) {
        super(node);
    }


    @Nullable
    public PsiReference getReference() {
        PsiReference[] references = getReferences();
        return references.length == 0 ? null : references[0];
    }



    @NotNull
    public PsiReference[] getReferences() {
        return ReferenceProvidersRegistry.getReferencesFromProviders(this);
    }


}

Yes, I realise that I don't need to go through the ReferenceProvidersRegistry - I could return references directly from these methods.

I've implemented a PsiReferenceContributor (see ApexReferenceContributor) which creates PSI References (see ApexClassNameReference & ApexInterfaceNameReference).
Debugging the code, I see that ApexClassNameReference and ApexInterfaceNameReference classes are being instantiated.  But non of the other methods are being called:
multiResolve(), resolve(), nor getVariants().

I'm testing it by running the plugin and creating three files:

Fred.cls with contents:
public class Fred { }

Mark.cls with contents:
public class Mark extends Fred {  }

ApexClass.cls with contents:
public class ApexClass { }

While I'm editing Mark.cls, I put the cursor on Fred and press Control-Space.  I would expect the ApexClass to come up in the list.  But I receive "No suggestions".  Is my assumption correct that ApexClass should come up?

Also renaming doesn't work - if I try and rename Fred, it only renames it in the current file.

I must be missing a key piece of the puzzle, but I can't figure it out!  Could you let me know what I'm missing?

Mark

4 comments
Comment actions Permalink

I figured it out......I knew it had to be something simple!

The problem was with my ApexReferenceContributor.  I had:

        registrar.registerReferenceProvider(
                psiElement(ApexExtendsClassName.class),
                new PsiReferenceProvider() {
                    @NotNull
                    @Override
                     public PsiReference[] getReferencesByElement(@NotNull PsiElement  element, @NotNull ProcessingContext context) {
                        return new PsiReference[] { new ApexClassNameReference((ApexExtendsClassName)element, element.getTextRange()) };
                    }
                }
        );


When I should have had:

        registrar.registerReferenceProvider(


                psiElement(ApexExtendsClassName.class),
                new PsiReferenceProvider() {
                    @NotNull
                    @Override
                    public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
                        return new PsiReference[] { new ApexClassNameReference((ApexExtendsClassName)element, new TextRange(0, element.getTextLength())) };
                    }
                }
        );


The TextRange passed into the PsiReference is the range inside the Element, not the range inside the parent file!

0
Comment actions Permalink

Oops - that's a common mistake, I have made that same mistake a few times myself too.
A 'trick' I like doing for when i'm quickly testing PsiReference text ranges is to simply set soft references to false, and resolve to null - that way it's very clear to see what ranges are being contributed :)

0
Comment actions Permalink

Indeed a common mistake. You can also use Tools|View PSI Structure, click on the element and see the references. Click on the reference to inspect and it will highlight the underlying TextRange.

0
Comment actions Permalink

Thanks for the tips guys!


0

Please sign in to leave a comment.