Skip to content

Commit

Permalink
ObjectFinal
Browse files Browse the repository at this point in the history
  • Loading branch information
xuwei-k committed Nov 29, 2023
1 parent f6c4f7a commit 6f3f212
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 0 deletions.
48 changes: 48 additions & 0 deletions input/src/main/scala/fix/ObjectFinalTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
rule = ObjectFinal
*/
package fix

object ObjectFinalTest {
final val a1: List[String] = List.empty[String] // assert: ObjectFinal
final val a2 = List.empty[String]

final def b1: List[String] = List.empty[String] // assert: ObjectFinal
final def b2 = List.empty[String] // assert: ObjectFinal
final def b3 = "a" // assert: ObjectFinal
final def b4 = 123 // assert: ObjectFinal

final val c1: Boolean = false
final val c2: Byte = 2
final val c3: Short = 3
final val c4: Char = 'x'
final val c5: Int = 5
final val c6: Long = 6L
final val c7: Float = 1.5f
final val c8: Double = 2.5

final val d1: scala.Boolean = false
final val d2: scala.Byte = 2
final val d3: scala.Short = 3
final val d4: scala.Char = 'x'
final val d5: scala.Int = 5
final val d6: scala.Long = 6L
final val d7: scala.Float = 1.5f
final val d8: scala.Double = 2.5

final val e1: _root_.scala.Boolean = false
final val e2: _root_.scala.Byte = 2
final val e3: _root_.scala.Short = 3
final val e4: _root_.scala.Char = 'x'
final val e5: _root_.scala.Int = 5
final val e6: _root_.scala.Long = 6L
final val e7: _root_.scala.Float = 1.5f
final val e8: _root_.scala.Double = 2.5

final val s1: String = "s"
final val s2: Predef.String = "s"
final val s3: scala.Predef.String = "s"
final val s4: _root_.scala.Predef.String = "s"
final val s5: java.lang.String = "s"
final val s6: _root_.java.lang.String = "s"
}
134 changes: 134 additions & 0 deletions rules/src/main/scala/fix/ObjectFinal.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package fix

import scala.meta.Defn
import scala.meta.Mod
import scala.meta.Pat
import scala.meta.Term
import scala.meta.Type
import scalafix.Patch
import scalafix.lint.Diagnostic
import scalafix.lint.LintSeverity
import scalafix.v1.SyntacticDocument
import scalafix.v1.SyntacticRule

object ObjectFinal {
private val constantTypes: Seq[Type] = {
val values = Seq(
"Boolean",
"Byte",
"Short",
"Char",
"Int",
"Long",
"Float",
"Double",
).map(Type.Name.apply)

Seq(
values.flatMap { x =>
Seq(
x,
Type.Select(
Term.Name("scala"),
x,
),
Type.Select(
Term.Select(
Term.Name("_root_"),
Term.Name("scala")
),
x
)
)
}, {
val str = Type.Name("String")

Seq(
str,
Type.Select(
Term.Name("Predef"),
str,
),
Type.Select(
Term.Select(
Term.Name("scala"),
Term.Name("Predef")
),
str
),
Type.Select(
Term.Select(
Term.Select(
Term.Name("_root_"),
Term.Name("scala")
),
Term.Name("Predef")
),
str
),
Type.Select(
Term.Select(
Term.Name("java"),
Term.Name("lang")
),
str
),
Type.Select(
Term.Select(
Term.Select(
Term.Name("_root_"),
Term.Name("java")
),
Term.Name("lang")
),
str
),
)
}
).flatten
}

private object FinalMod {
def unapply(values: List[Mod]): Option[Mod] = values.find(_.is[Mod.Final])
}
}

class ObjectFinal extends SyntacticRule("ObjectFinal") {

override def fix(implicit doc: SyntacticDocument): Patch = {
doc.tree.collect { case o: Defn.Object =>
o.templ.stats.collect {
case Defn.Val(
ObjectFinal.FinalMod(m),
List(Pat.Var(_: Term.Name)),
Some(tpe),
_
) if ObjectFinal.constantTypes.forall(_.structure != tpe.structure) =>
Patch.lint(
Diagnostic(
id = "",
message =
"redundant final https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#constant-expressions",
position = m.pos,
severity = LintSeverity.Warning
)
)
case Defn.Def.After_4_7_3(
ObjectFinal.FinalMod(m),
_,
_,
_,
_
) =>
Patch.lint(
Diagnostic(
id = "",
message = "redundant final",
position = m.pos,
severity = LintSeverity.Warning
)
)
}.asPatch
}.asPatch
}
}

0 comments on commit 6f3f212

Please sign in to comment.