How to resolve java method from custom language?

Hi all,

I'm writing a plugin for a custom language that can define services (DTOs, SQL requests etc) which are translated into Java code by a custom generator.

A service can be defined like this:

// In file CustomServices.svc

Service MY_SERVICE_NAME {
   // service content
}



The generated code looks like this:

public class CustomService {

  public List myServiceName(/* some parameters *) {
    ...
  }
}



In my custom language, I would like to implement "find usages" on services names (MY_SERVICE_NAME), and one of these usages (actually more like an "implementing method") is the myServiceName method. I know how to determine the fully qualified class name, the method name should be unique (but if needed I could get the exact parameters types). How can I find references to Java code?

Do I need to use PsiPolyVariantReference? If so, how do I create the returned ResolveResult[]?

Second question: if this is possible and if I can make it work, would it be possible to use the same code to add a "go to implementation" icon in the gutter, next to the service definition (and perhaps its counterpart "Go to service definition" in the Java code)?

Thanks for your help :)
5 comments
Comment actions Permalink

I was able to find the answer to the second question by myself: I used a LineMarkerProvider.

I am still looking for an answer to the first question, could somebody please help me?

Thanks
Bastien

0
Comment actions Permalink

If you want the Java method to be considered a reference to your code, then you don't need to provide your own reference (you actually can't - a Java method name is not a reference, and you can't inject your own reference there). Instead, you need to plug into the ReferencesSearch extension point, and locate the Java method when the element to which the references are searched is your MY_SERVICE_NAME.

To locate the Java method, use JavaPsiFacade.findClass() to find a class by its qualified name and then PsiClass.findMethodsByName() to locate a specific method.

0
Comment actions Permalink

Thanks Dmitry,

I am now able to retrieve an instance of PsiMethod in a custom referencesSearch that extends QueryExecutorBase.
But in processQuery(), I don't know how to retrieve a valid reference to use in consumer.process(). myMethod.getReference() returns null :(

What am I doing wrong?

PsiClass aClass = JavaPsiFacade.getInstance(elementToSearch.getProject()).findClass(myClassName, GlobalSearchScope.projectScope(elementToSearch.getProject())); PsiMethod method = aClass.findMethodsByName(myMethodName, false)[0]; consumer.process(method.getReference());



Thanks
0
Comment actions Permalink

It's correct that method.getReference() returns null. You need to return a custom PsiReference implementation that returns the PSI method from its getElement() implementation and your service from resolve().

0
Comment actions Permalink

I'm also facing a similar issue, I have implemented a custom Reference

public class CustomReference implements PsiReference {

    private final CustomType customType;

    private final PsiMethod javaImpl;

    public StepReference(CustomType customType, PsiMethod javaImpl) {

        this.customType = customType;

        this.javaImpl = javaImpl;

    }

    @Override

    public PsiElement getElement() {

        return customType;

    }

    @Override

    public TextRange getRangeInElement() {

        return customType.getTextRange();

    }

    @Nullable

    @Override

    public PsiElement resolve() {

        return javaImpl;

    }

    @NotNull

    @Override

    public String getCanonicalText() {

        return javaImpl.getName();

    }

    @Override

    public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {

        return null;

    }

    @Override

    public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {

        return null;

    }

    @Override

    public boolean isReferenceTo(PsiElement element) {

        return false;

    }

    @NotNull

    @Override

    public Object[] getVariants() {

        return new Object[0];

    }

    @Override

    public boolean isSoft() {

        return false;

    }

}


and in the query executor

public class CustomReferenceSearch extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {

    @Override

    public void processQuery(@NotNull ReferencesSearch.SearchParameters queryParameters, @NotNull Processor<PsiReference> consumer) {

        PsiElement elementToSearch = queryParameters.getElementToSearch();

        if (elementToSearch instanceof CustomType) {

            final CustomType customType = (CustomType) elementToSearch;

            PsiMethod javaImpl = Util.findImpl(customType, customType.getProject());

            if (javaImpl != null) {

                consumer.process(new CustomReference(customType, javaImpl));

            }

        }

    }

}


I have added

<referencesSearch implementation="CustomReferenceSearch"/>

in plugin.xml

when I debug I see that consumer.process() gets called but nothing happens when I cmd +B or cmd+click, could you tell me what I'm doing wrong?


Thanks

0

Please sign in to leave a comment.