New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Annotate closure args in Project with @DelegatesTo. #930
Conversation
This allows for IDEs like IntelliJ IDEA to provide better code completion inside these closures.
@melix Could I request a very quick review from you here (given that you wrote |
Sorry I forgot to answer this PR. I think it is valuable to add |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a very nice improvement but it needs further refinements:
- the strategy (optional parameter of
@DelegatesTo
) needs to be set toClosure.DELEGATE_FIRST
- it would be nice to have tests highlighting the fact that static compilation works with this (but not required)
@melix Thank you for your review! I will work on addressing your requests and get you an updated version of this pull request. |
@melix It turns out many delegates are actually For example (pardon my bad Groovy): HashMap<Integer,String> rs = [:]
rs[Closure.DELEGATE_FIRST] = "DELEGATE_FIRST"
rs[Closure.DELEGATE_ONLY] = "DELEGATE_ONLY"
rs[Closure.OWNER_FIRST] = "OWNER_FIRST"
rs[Closure.OWNER_ONLY] = "OWNER_ONLY"
rs[Closure.TO_SELF] = "TO_SELF"
task('q') {
println "task():"
println "strategy is ${rs[getResolveStrategy()]}"
println "delegate.getClass() ${delegate.getClass()}"
println "it.getClass() ${it.getClass()}"
println "this.getClass() ${this.getClass()}"
println "owner.getClass() ${owner.getClass()}"
println "(but owner.class is ${owner.class}...?)"
} yields:
I'm assuming, for cases like this, it's closer in spirit to mark this as |
Yes the delegation system of Gradle is a bit complex. Basically for methods that take an |
Also, add a test verifying Groovy static compilation's type- checking of these annotations.
information provided by closures annotated with @DelegatesTo and @ClosureArgs | ||
is actually _correct_. | ||
*/ | ||
// TODO? How to validate @DelegatesTo strategy? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't figure out a way to validate @DelegatesTo
with this approach, unfortunately, nor how to do any kind of meaningful check for static compilation failures. But, you can experiment with modifying the @DelegatesTo
and @ClosureParams
in Project
, and watch the effects on this test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@melix Any thoughts on this TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we need to call methods from the delegate directly in the closure (without it
).
* | ||
* <p>Here, the sole parameter for Closure c would be of type R, as R is the return type of foo.</p> | ||
*/ | ||
public final class ReturnType extends SingleSignatureClosureHint { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't figure out a way to use @ClosureParams
and directly specify the type in a strongly-typed way, as done with @DelegatesTo
. Since it seems to be a common pattern in Gradle to have the closure's argument be the same as the method's return type, I created this. For cases this did not fit, I used SimpleType
. If there's a cleaner way to do this or you'd prefer a different approach just let me know.
@@ -1138,7 +1141,7 @@ | |||
* | |||
* @param closure The closure to call. | |||
*/ | |||
void beforeEvaluate(Closure closure); | |||
void beforeEvaluate(@ClosureParams(value = SimpleType.class, options = {"org.gradle.api.Project"}) Closure closure); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The delegate for this seems to be the build script class itself, which didn't end up being all that useful to specify here, and was also marked internal. So, I left off the @DelegatesTo
. Same with afterEvaluate
and container
.
@melix This should be ready for review but if you need any other changes please just let me know. |
@melix Would you mind finishing off this PR? |
@melix Any chance this can still make it into 4.0-RC1? |
@bmuschko Finally took time to finish the review. There are some pitfalls, which I discovered with the statically compiled Gradle build script experiment months ago, but the changes LGTM. |
Makes code completion in IDE less bad. (also fixed a tiny typo)
Any of the checked boxes below indicate that I took action:
./gradlew quickCheck
I believe this is a very trivial change. (No API changes or functionality changes. Just a better IDE experience). But, please let me know if more is needed.