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
beforemy.Inner
, which works but is not a viable solution since I have multiple methodsdoIt
(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
(ofprintln
) - 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
howclazz
, 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
.
source to share