Create a method via GDSL script that has a delegate close option

Using the (hardly documented) gdsl scripts for Intellij it is possible to add dynamic methods to the class:

contributor(context(ctype: "my.Type")) {
  method name: "doIt", params: [body: {}], type: void
}

      

Closure delegation can also be configured:

contributor(context(scope: closureScope())) {
  def call = enclosingCall("doIt")
  if (call) {
    def method = call.bind()
    def clazz = method?.containingClass
    if (clazz?.qualName == 'my.Type') {
      delegatesTo(findClass('my.Inner'))
    }
  }
}

      

What, When doIt

is a method defined in code (not dynamically added) also works as designed.

However, when used closureScope

with a previously created method, the class method is containing

always null

, which means that I cannot safely delegate within the addressable closure my.Inner

.

I want to add a dynamic method equivalent to:

void doIt(@DelegatesTo(my.Inner) Closure)...

      

those. I want this method to be available when the code completes (it works) and inside the generated closure I want the code fix to be done when the methods are my.Inner

called.

So far I have tried different approaches:

  • include @DelegatesTo annotation in parameter definition
  • try more esoteric approaches when looking for the owner of the closure, which fails because GrMethodCall just doesn't have a parent
  • unconditionally delegate all locks named doIt

    before my.Inner

    , which works but is not a viable solution since I have multiple methods doIt

    (on different classes) delegating different targets.

So how can I get IDEA to behave as expected and delegate the correct target?


Edit to make it clear:

Considering the following classes:

package my
class Type {
    void doIt(Closure) {}
}
class Inner {
    void inInner() {}
}

      

and the following gdsl:

contributor(context(scope: closureScope())) {
  def call = enclosingCall("doIt")
  if (call) {
    def method = call.bind()
    def clazz = method?.containingClass
    println clazz?.qualName
    if (clazz?.qualName == 'my.Type') {
      delegatesTo(findClass('my.Inner'))
    }
  }
}

      

when i start typing a new script:

new Type().doIt {
    inInner()
}

      

When inside a closure, I get this:

  • code completion for inInner

  • inInner

    displayed as valid
  • Console output when run with idea.bat from command line shows the line my.Type

    (of println

    )
  • Ctrl-B inInner

    does not correctly link to source code.

(The same behavior can be achieved without gdsl with annotations Closure parameter in the method doIt

to @DelegatesTo(Inner)

)

However, I don't want to manually include the method doIt

in the Source Type, it is generated by the AST Transformation, so my source file now looks like this:

package my
class Type {
}
class Inner {
    void inInner() {}
}

      

I can tell IntelliJ about the new method using the following gdsl snippet

contributor(context(ctype: "my.Type")) {
  method name: "doIt", params: [body: {}], type: void
}

      

The IDE now correctly recognizes the doIt method with a close parameter. However, inside the Closure, the following happens:

  • sometimes code completion shows inInner

    , sometimes after change something is not (when using the source code to fix the type, it was shown but later declared "unresolved", after going through the code changes of this edited For example, it is no longer shown ...)
  • Even if shown, is inInner

    displayed with the decoration "cannot resolve symbol"
  • the console shows null

    how clazz

    , that is, the method was found, but not associated with the owner of the ASTNode
  • Ctrl-B does not refer to the corresponding method in Inner

So what I want is the same behavior for the injected method doIt

(via Gdsl) as with the method included in the source, i.e. I want gdsl to inject a doIt

delegate closure method (for Inner) into the class type

.

+3


source to share


1 answer


This worked for me adding ctype to the scope you were looking for the class type from the method



contributor(context(scope: closureScope(), ctype: 'my.Type')) {
  def call = enclosingCall("doIt")
  if (call) {
      delegatesTo(findClass('my.Inner'))
   }
}

      

+1


source







All Articles