-
Notifications
You must be signed in to change notification settings - Fork 185
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
Add support for linters #291
Conversation
This looks great so far 👍 New lint rules look very straightforward to implement. |
Do you think it's confusing that a linter |
That’s tricky as sometimes we will want a lint or be a rewrite (or have a rewrite associated) but not always. I’m heading off to bed but if I think of a better name I will let you know. In some ways this reminds me of a more powerful version of a classic regex. You have your capture groups, and optionally your replacement but that still doesn’t immediately suggest a better name to me. It’s possible it could be generalized to some sort of Matcher with an optional Lint and an optional Rewrite to convey the idea that we always have to match a pattern of code, then we can either warn, rewrite, or both. |
Borrowing terminology from pylint, we could use |
I agree that The confusion arises by the strange path we're taking: usually projects start as linters and then add some fixing capabilities, but scalafix started from the fixing part and we're retrofitting the linting. Instead of having a unique concept, I would rather see two different entities: a WDYT? |
I am not sure about separating rewrites from linters since that will leave us without a good name for rewrites that emit linter messages (like RemoveXmlLiterals in this PR). The API is identical for both linters and rewrites, so I would edge towards using a unified name. Maybe |
|
Agreed, I'm leaning towards adding more metadata methods on
|
OT: Preparing a talk on Scalafix is very entertaining these days. I need a Slidefix tool :P |
I opened #293 to continue our discussion on renaming |
🤣 I apologize for the endless changes, I'm not good at sitting down and designing thoroughly before writing code. |
No apologies needed. I would be more worried about an exciting project slowing down in its early stages because of minor compatibility issues (just don't rename stuff 10 minutes before my talk! I'll keep an eye on you 👀 ) |
Clean up repo in preparation for #291
All right, I think this PR is ready now :) I ended up doing a lot of testing infrastructure changes in this PR. This may pollute the actual diff but it gives me a lot more confidence the changes work as intended. I am super happy with the CliTest rewrite and the lint message assertions via comments in scalafix-testkit are quite nice too. The main data structures went through some renaming in the final commits while I was writing docs
Escape hatches #241 are still a TODO, but those will have to wait for another PR. |
RewriteName is a wrapper around a non-empty list of strings instead of being a single string. Original names are preserved when composing multiple RewriteNames.
New package scalafix.lint with data structures for emitting messages from linters: - LintID: uniquely identifies a certain kind of linter message, owned by a rewrite. A LintID is attached to a default warning/error severity but can be configured to another category with `lint.ignore/warning/error = [ LintID ]` - LintMessage: an instance of LintID with a customized message at a particular position. A LintMessage can be created wit LintID.at(String/Position). - A LintMessage can be turned into a Patch with ctx.lint(LintMessage). LintMessages don't report to the console until Rewrite.apply is called. To accommodate linter development, scalafix-testkit now enforces that expected warnings/errors are documented in the input sources with a trailing `// scalafix: error/warning` comment. scalafix-cli returns a non-zero exit code of kind "LinterError" when a linter reports an error.
- RewriteName is a list of RewriteIdentifier. - RewriteIdentifier is a name + optional deprecation warning. This makes it possible to rename a rewrite without breaking peoples config. - Rewrite.empty has name RewriteName.empty, which is an empty list of RewriteIdentifier.
This change allows rewrites to change their names without breaking compatibility. Users using the old name will receive deprecation warnings and have opportunity to switch to the new name.
unit/test has fixtures to build SemanticCtx, which will come in handy to test the cli.
The cli tests have in need for a rewrite for a long time. This commits creates a helper method to easily construct a fixture and run assertions against the expected output.
Instead of using LintID.owner, the RewriteCtx.printMessages takes an `owner: RewriteName` argument. This results in a simpler LintID data structure.
"Category" is misleading.
LintCategory is more suitable since it is a category of LintMessages.
I've been meaning to rename this rewrite for a while but wasn't satisfied that this would break people's configuraiton. I wanted to solve this potentially common problem in the future more elegantly. Now that rewrites can have multiple names and names can have deprecation warnings, this commits tests that it indeed works as expected.
- doc polish - Require `// scalafix: Rewrite.LintCategory` assertions instead of warning/error. This is more robust. - Rename VolatileLazyVal to DottyVolatileLazyVal in tests, I noticed because of deprecation warnings getting printed out. - Don't print out lint messages in scalafix-testkit by default, if you have a lot of assertions then the console gets flooded with too many messages.
- remove unused imports with scalafix (hurray!) - refactor build.sbt a bit - polish new doc entries - Remove unused Patch.applyInternal
I will go ahead and merge this to unblock other work that relies on the new cli testing infrastructure. I am happy to continue iterating on the lint API :) |
Just opening this PR to show progress
.deprecated
.