-
Notifications
You must be signed in to change notification settings - Fork 1.2k
detect and ban wildcard imports in Java #14804
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
Conversation
This PR does not have an entry in lucene/CHANGES.txt. Consider adding one. If the PR doesn't need a changelog entry, then add the skip-changelog label to it and you will stop receiving this reminder on future updates to the PR. |
Can we consider ast-grep for this? it is really fast and doesn't require regular expressions, has plugins for editors. I wrote a rule for this in less than a minute: id: wildcard-import-not-allowed
language: java
rule:
kind: asterisk
inside:
kind: import_declaration
severity: error
message: don't use wildcard imports
note: please use full import instead
url: https://whatever/explanation |
I'll take a look, sure. I'll also try to figure out why the heck spotless isn't behaving the way it should. |
Thanks for playing with it. I would be happy to try to write ast-grep rules to try to replace some of the slower error-prone checks, or whatever else (nocommit checks etc). We could install the package via pip or npm in the GH actions to support the checker. At just a glance, many of the rules are basically trivial e.g. https://errorprone.info/bugpattern/EqualsNull. From what I remember, each check has a high overhead for errorprone which I don't believe is the case for ast-grep. I know I'm oversimplifying it, but I assume each file is parsed only once and then all rules run similar to https://tree-sitter.github.io/tree-sitter/using-parsers/queries/1-syntax.html, but without the s-expressions :) |
Well, if this patch goes in, all it takes to add a rule is to create a new file in gradle/validation/ast-grep - it should be picked up automatically. We can also make ast-grep a requirement (much like python, perl and git) in the long term if it proves to be beneficial. I've taken a look at the tree sitter too, very interesting stuff. Gotta love how with all the cool languages out there, it's still C that prevails. :) |
Another related idea here is to prevent any IDE from automatically adding the *'s we don't want. Eclipse's default limit is 99 imports before it starts doing this... of course user can change, and some rare files might exceed this. there's a way to bump it to huge value (e.g. Integer.MAX_VALUE) in our eclipse settings, i think, but i don't have a concrete solution: https://github.com/eclipse-jdtls/eclipse.jdt.ls/blob/0b3651f030e2e68e43019268f35880a07aa7a8c5/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java#L345-L367 I don't know how intellij behaves here or if we can prevent similar behavior. All this stuff can be followups, really, I'm just brainstorming. Thanks for the ast-grep though!!! Gives me a way to help speed up the checks :) I will leave a few comments, not review ones intended to block the change. I can help out with followup PRs. |
@@ -0,0 +1,2 @@ | ||
ruleDirs: | ||
- ./rules No newline at end of file |
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've found the built-in self-test to be essential for having and keeping correct rules. It takes milliseconds and they are easy to write.
- ./rules | |
- ./rules | |
testConfigs: | |
- testDir: ./tests |
I run these with ast-grep test --skip-snapshot-tests
before the ast-grep scan
.
For a rule like this one, I would add tests (untested!) like this: tests/errorprone.yml
(which would test rules in rules/errorprone.yml
. I organize them this way with ---
yaml doc separator between the rules in both files. For multiline tests, I use yaml literal style (|
): https://yaml.org/spec/1.2-old/spec.html#id2795688
---
# test wildcard import detector
id: wildcard-import-not-allowed
valid:
- import foo.bar.Baz;
- import static foo.bar.Baz;
invalid:
- import foo.bar.*;
- import static foo.bar.*;
---
# test for another error prone rule
id: some-other-errorprone-rule
invalid:
- |
if (x.equals(null) {
}
- |
foo = x.equals(null) ? 1 : 2;
# ...
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 run these with ast-grep test --skip-snapshot-tests before the ast-grep scan.
We can integrate this check into gradle as well. These are nice indeed - I've seen the docs on the tool.
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've added it, nice.
I've forked the ast-grep thing into a separate PR - #14808. I think we can merge that one in, then I can apply a smaller patch for wildcards, using your rule. |
We should be able to make it easier for IntelliJ to do the right thing without too much trouble. One option is to use I can take a shot at a separate PR to help out there. |
I've never used this plugin - have it on my "to-check" list (!). It would be awesome to provide more reasonable IntelliJ defaults. My experience with using google-java-format plugin is that once you enable it, the import section formatting settings are completely ignored... |
Co-authored-by: Robert Muir <rcmuir@gmail.com>
Ok. I think this one is ready. |
severity: error | ||
message: don't use wildcard imports | ||
note: please use full imports instead | ||
url: https://google.github.io/styleguide/javaguide.html?cl=head#s3.3.1-wildcard-imports |
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 can see pointing at the style guide, but as far as being practical, i wonder if we can name the file errorprone.yml and name the checks accordingly (e.g. WildcardImport
and link to their https://errorprone.info/bugpattern/WildcardImport url.
It is just how i've been organizing them, after seeing others use similar approach. I also think the errorprone URL is more helpful to end-user in fixing such issues (specs are more difficult to read), but that's just me.
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.
Up to you, entirely. I just pasted... something. :)
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.
Done.
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.
we can always change it. that particular description is really cool too, because of how meta this PR is. By banning these wildcards, we can do more with these simple rules :)
Just as an example, you could write unused import rule which would work correctly (if you wanted to), whereas with wildcards its not reasonable.
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.
Oh, if you'd like to rename the rules - feel free to just commit whatever it is your gut tells you. I think I'm done here - once you think it's ready, just squash to main, please. Thanks!
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.
let's just commit yours, i'll try to see if i can find some easy-wins in the errorprone rule list and organize while I'm there.
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.
Thanks for coming up with this great idea - it seems like it opens up a lot of new possibilities. Definitely better than the custom formatter step I initially added.
FYI - spotless runs google java format in a single-thread, that's part of the reason it's sluggish. But it's still an order of magnitude slower than the c parser. I ran this, for the fun of it (this uses multiple threads for parsing):
The user time - compared to tree-sitter's 7 seconds - is rather pale. |
@dweiss yeah, the parsers are generally fast. and the java one in particular is very nice. Of course they are doing a lot less, too. parser test framework tracks the performance in terms of MB/s and warns if the speed gets too low:
|
Spotless now supports removing wildcard diffplug/spotless#2517 from 7.1.0. We can use the same |
@owaiskazi19 thank you for the heads up. I opened #14960 for this. I saw the spotless 7.1 PR go through but unfortunately nothing in the release notes in the dependabot PR about a new wildcard-remover feature: #14956 |
Except we're now using custom code to call into google java format... Eh. |
Hmm... looking at the diff, the added step just removes wildcard imports - it doesn't resolve them (like intellij or eclipse would)? I don't know if this is that helpful. |
Yeah, just removing them isn't "fixing" :) |
Fixes #14553.
I'm not completely happy with this. For some reason, the custom formatting step always triggers full spotless run - incremental mode doesn't work.
The detection is also costly (regexp over the entire codebase); this could be probably simplified to line-by-line scanning and a heuristic to short-circuit early when import statements are no longer possible...