Plugin dev

Not sure if this is the right forum for it, but I'm writing a plugin in Java that uses the scala plugin to query PSI and so on (cucumber for scala).

I have two PSI related issues that I'm unable to resolve:

- I have a QueryExecutor to find step def usages in feature files. In the Java plugin, this gets a PsiMethod and all is well. In Scala, it gets a ScReferencePattern. How do I go from this to either ScMethod, ScMethodCall, or any other navigation I need to do to ultimately get the method call parameters?

- Similarly, elsewhere I have a ScMethodCall, and I'm trying to find out where this call is actually defined, and want to check the package/class of the method call. For example:

class Foo
def bar(val: String) = { ... }

class Wibble extends Foo {

bar("xyz")

bar resolves to PsMethodCall, I'd be able to determine that it's a method call to Foo.

6 comments

Hi!

First of all, there exists a quite useful guide for IDEA plugin development ("References and Resolve" in Developing Custom Language Plugins for IntelliJ IDEA is especially relevant).

Another useful thing is PSI viewer.

Scala Language Specification may be also helpful.

Basically, all you need to do, is to:

  • find a PsiReference instance within a method call (it's a first child element in ScMethodCall),
  • resolve that reference by calling "resolve" and get a class member,
  • call "contatiningClass" on that member, and get a enclosing class,
  • call "qualifiedName" on the class to get a fully qualified class name.


Keep in mind, that the steps above are for the simple case, and Scala syntax can be rather manifold (check the Scala plugin code for examples).

You may provide specific code snippets and we will take a good look at them.

0

Great, thanks! This solves the second question I have.

I'm still unable to figure out how to go from PsiReferencePattern to get the arguments for the call. An example to help illustrate. Putting the following in Psi Viewer:

package scaladefs

import cucumber.api.scala.{EN, ScalaDsl}
import cucumber.api.Scenario

class CalculatorStepDefs extends ScalaDsl with EN {

  Then("^the result is (\\d+)$") {
  }
}



What I'd like is to get the highlighted part (the parameter to Then).


In PsiViewer, everything looks fine. I have MethodCall which has ReferenceExpression and ArgumentList as children, so I can get the arg just fine.

However, when I look at the actual psi (not in psi viewer), I don't have a MethodCall, instead I have a ScReferencePattern, and I can't figure out the right sequence of calls to go from ScReferencePattern to the string parameter I'm trying to get a hold of.

0

Runtime PSI structure should completely match the structure in the PSI viewer.

Here's how you can verify that:

    val s = """package scaladefs
              |
              |import cucumber.api.scala.{EN, ScalaDsl}
              |import cucumber.api.Scenario
              |
              |class CalculatorStepDefs extends ScalaDsl with EN {
              |
              |  Then("^the result is (\\d+)$") {
              |  }
              |}""".stripMargin

    val file = ScalaPsiElementFactory.parseFile(s, getManager)

    print(DebugUtil.psiToString(file, true))


Here's an excerpt of the resulting strucutre:

        ScTemplateBody
          PsiElement({)('{')
          MethodCall
            MethodCall
              ReferenceExpression: Then
                PsiElement(identifier)('Then')
              ArgumentList
                PsiElement(()('(')
                Literal
                  PsiElement(string content)('"^the result is (\\d+)$"')
                PsiElement())(')')
            ArgumentList
              BlockExpression
                PsiElement({)('{')
                PsiElement(})('}')
          PsiElement(})('}')


So, everything is basically the same as I outlined in my previous message.

Probably you were inspecting PSI for a different piece of code (or modified PSI).

0

I'm getting the element in a callback. In my plugin.xml I have:

  <extensions defaultExtensionNs="com.intellij">
    <referencesSearch implementation="MyStepDefinitionSearch"/>
  </extensions>


My implementation class:

public class MyStepDefinitionSearch implements QueryExecutor<PsiReference, ReferencesSearch.SearchParameters> {
  @Override
  public boolean execute(@NotNull final ReferencesSearch.SearchParameters queryParameters, @NotNull final Processor<PsiReference> consumer) {
    final PsiElement myElement = queryParameters.getElementToSearch();


myElement here is a ScReferencePattern, not a ScMethodCall as I was hoping it would be. The callback is called whenever I click on the 'When' in the scala source.

0

You may use the following to check the full PSI stucture:

System.out.print(DebugUtil.psiToString(myElement.getContainingFile(), true))
0

Yeah that prints out the PSI for EN.scala. I guess the problem I'm having then is that the callback is giving me the actual invocation target (When in EN.scala) rather than its actual usage (ScMethodCall). So I guess the problem is my usage of referencesSearch in plugin.xml.

What I'd like is to be able to click on the When and have find usages find the string param in .feature files.

0

Please sign in to leave a comment.