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

Suppression comments sometimes suppress more than intended #2101

Open
coreywoodfield opened this issue Oct 11, 2024 · 0 comments
Open

Suppression comments sometimes suppress more than intended #2101

coreywoodfield opened this issue Oct 11, 2024 · 0 comments

Comments

@coreywoodfield
Copy link

coreywoodfield commented Oct 11, 2024

I have discovered that sometimes, suppression comments suppress more than they are (ostensibly) intended to suppress. Consider the following simple scalafix rule that simply disallows the use of the name foo, and test file we will run it on:

Rule.scala

import scala.meta.*
import scalafix.v1.*

class Test extends SyntacticRule("Test") {
  override def fix(implicit doc: SyntacticDocument): Patch = {
    doc.tree.collect { case t @ Term.Name("foo") =>
      Patch.lint(Diagnostic("foundFoo", s"don't use foo", t.pos))
    }.asPatch
  }
}

Test.scala

class Test {
  List().foreach { value =>
    foo
    foo
    foo
  }
  () match {
    case "end comment works as expected" =>
      foo
      foo
    case "end comment works as expected" => {
      foo
      foo
    }
  }
  () match {
    case "end comment suppresses the rule in the whole case" =>
      foo
      foo
  }
}

We run the rule on the file, and it works as expected: we get one linting error for every use of foo. We don't want to clean these up right away, so we run again with --auto-suppress-linter-errors. We end up with

class Test {
  List().foreach { value =>
    foo/* scalafix:ok */
    foo/* scalafix:ok */
    foo/* scalafix:ok */
  }
  () match {
    case "end comment works as expected" =>
      foo/* scalafix:ok */
      foo/* scalafix:ok */
    case "end comment works as expected" => {
      foo/* scalafix:ok */
      foo/* scalafix:ok */
    }
  }
  () match {
    case "end comment suppresses the rule in the whole case" =>
      foo/* scalafix:ok */
      foo/* scalafix:ok */
  }
}

So far so good. The next time we run the linting, however, we get something unexpected: three warnings

/path/to/Test.scala:3:8: warning: [UnusedScalafixSuppression] Unused Scalafix suppression, this can be removed
    foo/* scalafix:ok */
       ^^^^^^^^^^^^^^^^^
/path/to/Test.scala:4:8: warning: [UnusedScalafixSuppression] Unused Scalafix suppression, this can be removed
    foo/* scalafix:ok */
       ^^^^^^^^^^^^^^^^^
/path/to/Test.scala:18:10: warning: [UnusedScalafixSuppression] Unused Scalafix suppression, this can be removed
      foo/* scalafix:ok */
         ^^^^^^^^^^^^^^^^^

... what? Those were just added.

It turns out that the comment after the last statement of some blocks is interpreted as applying to the whole block, rather than just to the last statement. If we appease the rule, we end up with something like

class Test {
  List().foreach { value =>
    foo
    foo
    foo/* scalafix:ok; applies to whole block */
  }
  () match {
    case "end comment works as expected" =>
      foo/* scalafix:ok */
      foo/* scalafix:ok; doesn't apply to whole block */
    case "end comment works as expected" => {
      foo/* scalafix:ok */
      foo/* scalafix:ok; doesn't apply to whole block */
    }
  }
  () match {
    case "end comment suppresses the rule in the whole case" =>
      foo
      foo/* scalafix:ok; applies to whole block */
  }
}

Adding new foo references inside the foreach or inside the last match does not cause the rule to emit a new error, whereas it arguably should. I think in general, a comment at the end of a block that is not delimited by braces should probably be treated as a comment on the last statement of that block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants