Skip to content
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

Merged
merged 18 commits into from
Aug 18, 2017
Merged

Add support for linters #291

merged 18 commits into from
Aug 18, 2017

Conversation

olafurpg
Copy link
Contributor

@olafurpg olafurpg commented Aug 16, 2017

Just opening this PR to show progress

  • clean up commit history
  • move scalafix.internal.rewrite to separate PR (see Clean up repo in preparation for #291 #294 )
  • improve RewriteName, use List[Name] and Name has fields like .deprecated.
  • more linter tests
  • LintCategory.Info
  • remove akka from build import?
  • scalafix.lint docstrings

@ShaneDelmore
Copy link
Contributor

This looks great so far 👍 New lint rules look very straightforward to implement.

@olafurpg
Copy link
Contributor Author

olafurpg commented Aug 17, 2017

Do you think it's confusing that a linter extends Rewrite? I've considered if we need a better name.

@ShaneDelmore
Copy link
Contributor

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.

@olafurpg
Copy link
Contributor Author

Borrowing terminology from pylint, we could use Checker (https://pylint.readthedocs.io/en/latest/how_tos/custom_checkers.html). I personally prefer sticking to Rewrite however.

@gabro
Copy link
Collaborator

gabro commented Aug 17, 2017

I agree that Rewrite is confusing for rules that check only.

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 Checker, Rule, or whatever and a Rewrite associated to it, but I'm not sure we have a clear way of drawing the line between the two.

WDYT?

@olafurpg
Copy link
Contributor Author

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 scalafix.Rule?

@gabro
Copy link
Collaborator

gabro commented Aug 17, 2017

Rule sounds good. It may be useful (for future integrations or even for the readme) to include a flag that specifies whether this is a pure linting rule or whether it includes fixes as well.

@olafurpg
Copy link
Contributor Author

Agreed, I'm leaning towards adding more metadata methods on Rewrite (or Rule if we go that route) such as

Rewrite.description: String
Rewrite.lintMessages: List[LintMessage]
...

@gabro
Copy link
Collaborator

gabro commented Aug 17, 2017

OT: Preparing a talk on Scalafix is very entertaining these days. I need a Slidefix tool :P

@olafurpg
Copy link
Contributor Author

I opened #293 to continue our discussion on renaming Rewrite

@olafurpg
Copy link
Contributor Author

OT: Preparing a talk on Scalafix is very entertaining these days. I need a Slidefix tool :P

🤣

I apologize for the endless changes, I'm not good at sitting down and designing thoroughly before writing code.

@gabro
Copy link
Collaborator

gabro commented Aug 17, 2017

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 👀 )

olafurpg added a commit that referenced this pull request Aug 17, 2017
@olafurpg olafurpg changed the title [WIP] Add infrastructure for Linters Add support for linters Aug 17, 2017
@olafurpg
Copy link
Contributor Author

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

  • LintCategory: a certain kind/type of lint message
  • LintMessage: a (message, position, LintCategory) triplet.

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
@olafurpg
Copy link
Contributor Author

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 :)

@olafurpg olafurpg merged commit b42cf5c into scalacenter:master Aug 18, 2017
@olafurpg olafurpg deleted the messages branch August 18, 2017 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants