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

#238 Rule to remove unused local val and var #367

Merged
merged 3 commits into from
Sep 23, 2017
Merged

#238 Rule to remove unused local val and var #367

merged 3 commits into from
Sep 23, 2017

Conversation

DanielaSfregola
Copy link
Contributor

This PR implements the rule described in #238.

In the specific, it removed unused local vals and vars. If litteral expressions are involved, the whole expression is removed, otherwise only the val definition is removed.

I'll try to send another PR for unused def/trait/classes in the near future.

Copy link
Collaborator

@gabro gabro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution @DanielaSfregola! 🙏
I left a few comments ;)

}

override def fix(ctx: RuleCtx): Patch = {
ctx.debugIndex()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot this in?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, my bad! Removing it

object RemoveUnusedTerms {

def foo {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to remove the leading spaces including the newline (like I did in my presentation from yesterday)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely need a ctx.removeLeading or something

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I suggested at the spree that we leave the leading space unchanged until we add better utilities to handle this.

println(1)
}

val unused = 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this stay?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I could see, this wasn't flagged by the compiler as unused. But I have to admit this looks a bit weird. // cc @olafurpg ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a globally accessible val, it could be used by another project.

private def removeLiterals(rhs: Term): String =
rhs match {
case Lit(_) => ""
case r => r.syntax
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're potentially modifying the syntax of the original rhs here, I would probably change approach and produce an Option[Patch]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose that we only remove the necessary tokens (val/identifier/=) and leave the rhs unchanged, there may be other rules touching the tokens inside the rhs.

Copy link
Contributor

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this contribution @DanielaSfregola ! If we can minimize the number of removed tokens, that is, only remove val x = in val x = rhs.blah(..) instead of replacing all tokens then I think we are good to merge this 😄

If you are feeling ambitious, we can also handle a few other unused cases such as unused parameters. But we can leave that for a separate PR

private def removeLiterals(rhs: Term): String =
rhs match {
case Lit(_) => ""
case r => r.syntax
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose that we only remove the necessary tokens (val/identifier/=) and leave the rhs unchanged, there may be other rules touching the tokens inside the rhs.

override def fix(ctx: RuleCtx): Patch = {
ctx.debugIndex()
ctx.tree.collect {
case i: Defn.Val if isUnused(i) => ctx.replaceTree(i, removeLiterals(i.rhs))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It requires a bit more work, but as I mention above, I think it makes sense to ctx.removeToken only for the tokens that should be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like i.tokens.filterNot(i.rhs.tokens.contains).map(ctx.removeToken) might do the trick.

object RemoveUnusedTerms {

def foo {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I suggested at the spree that we leave the leading space unchanged until we add better utilities to handle this.

println(1)
}

val unused = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a globally accessible val, it could be used by another project.

Copy link
Contributor

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 Great work @DanielaSfregola !

Only need to fix the build on 2.11 and then we're good to merge :)

build.sbt Outdated
@@ -306,7 +306,7 @@ lazy val testsInput = project
scalacOptions += s"-P:semanticdb:sourceroot:${sourceDirectory.in(Compile).value}",
scalacOptions ~= (_.filterNot(_ == "-Yno-adapted-args")),
scalacOptions += "-Ywarn-adapted-args", // For NoAutoTupling
scalacOptions += "-Ywarn-unused-import", // For RemoveUnusedImports
scalacOptions += "-Ywarn-unused", // For RemoveUnusedImports and RemoveUnusedTerms
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we need to keep -Ywarn-unused-import for 2.11 https://travis-ci.org/scalacenter/scalafix/jobs/278586505

unusedTerms.contains(defn.pos)

private def removeDeclarationTokens(i: Defn, rhs: Term): Tokens = {
val startDef = i.tokens.start
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL I have not noticed Tokens.start 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I struggled a bit with this function as Tokens.filter returns a IndexSeq[Token] rather than a Tokens. Also, the constructor of Tokens is private to the package meta, so writing something like

i.tokens.filterNot(rhs.tokens.contains)

would have been nicer but unfortunately it didn't quite work :(

@olafurpg
Copy link
Contributor

Thank you! 🎆

@olafurpg olafurpg merged commit 55e1fd1 into scalacenter:master Sep 23, 2017
@olafurpg olafurpg mentioned this pull request Oct 6, 2017
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