From 6842afb345ee69aa6081e9764a087c164ba9402e Mon Sep 17 00:00:00 2001 From: Thibault Czarniak Date: Thu, 12 Sep 2024 17:30:37 +0200 Subject: [PATCH] Added ComparisonToEmptyList and ComparisonToEmptySet --- .../scala/fix/ComparisonToEmptyList.scala | 26 ++++++++++++ .../main/scala/fix/ComparisonToEmptySet.scala | 22 ++++++++++ .../META-INF/services/scalafix.v1.Rule | 4 +- .../scala/fix/ComparisonToEmptyList.scala | 41 +++++++++++++++++++ .../main/scala/fix/ComparisonToEmptySet.scala | 39 ++++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 input/src/main/scala/fix/ComparisonToEmptyList.scala create mode 100644 input/src/main/scala/fix/ComparisonToEmptySet.scala create mode 100644 rules/src/main/scala/fix/ComparisonToEmptyList.scala create mode 100644 rules/src/main/scala/fix/ComparisonToEmptySet.scala diff --git a/input/src/main/scala/fix/ComparisonToEmptyList.scala b/input/src/main/scala/fix/ComparisonToEmptyList.scala new file mode 100644 index 0000000..6735953 --- /dev/null +++ b/input/src/main/scala/fix/ComparisonToEmptyList.scala @@ -0,0 +1,26 @@ +/* +rule = ComparisonToEmptyList + */ +package fix + +object ComparisonToEmptyList { + val a = List(1, 2, 3) + + val b = a == List() // assert: ComparisonToEmptyList + val c = List() == a // assert: ComparisonToEmptyList + + val d = a == List.empty // assert: ComparisonToEmptyList + val e = List.empty == a // assert: ComparisonToEmptyList + + val f = a == Nil // assert: ComparisonToEmptyList + val g = Nil == a // assert: ComparisonToEmptyList + + val h = List.apply() == a // assert: ComparisonToEmptyList + val i = a == List.apply() // assert: ComparisonToEmptyList + + val j = a == List(3, 4) // scalafix: ok; + val k = List(3, 4) == a // scalafix: ok; + val l = a != List(3, 4) // scalafix: ok; + val m = List(3, 4) != a // scalafix: ok; + +} diff --git a/input/src/main/scala/fix/ComparisonToEmptySet.scala b/input/src/main/scala/fix/ComparisonToEmptySet.scala new file mode 100644 index 0000000..4bffdd8 --- /dev/null +++ b/input/src/main/scala/fix/ComparisonToEmptySet.scala @@ -0,0 +1,22 @@ +/* +rule = ComparisonToEmptySet + */ +package fix + +object ComparisonToEmptySet { + val a = Set(1, 2, 3) + + val b = a == Set() // assert: ComparisonToEmptySet + val c = Set() == a // assert: ComparisonToEmptySet + + val d = a == Set.empty // assert: ComparisonToEmptySet + val e = Set.empty == a // assert: ComparisonToEmptySet + + val h = Set.apply() == a // assert: ComparisonToEmptySet + val i = a == Set.apply() // assert: ComparisonToEmptySet + + val j = a == Set(3, 4) // scalafix: ok; + val k = Set(3, 4) == a // scalafix: ok; + val l = a != Set(3, 4) // scalafix: ok; + val m = Set(3, 4) != a // scalafix: ok; +} diff --git a/rules/src/main/resources/META-INF/services/scalafix.v1.Rule b/rules/src/main/resources/META-INF/services/scalafix.v1.Rule index deb8b6a..5ab490d 100644 --- a/rules/src/main/resources/META-INF/services/scalafix.v1.Rule +++ b/rules/src/main/resources/META-INF/services/scalafix.v1.Rule @@ -60,4 +60,6 @@ fix.BooleanParameter fix.BoundedByFinalType fix.BrokenOddness fix.ClassNames -fix.CollectionNamingConfusion \ No newline at end of file +fix.CollectionNamingConfusion +fix.ComparisonToEmptyList +fix.ComparisonToEmptySet \ No newline at end of file diff --git a/rules/src/main/scala/fix/ComparisonToEmptyList.scala b/rules/src/main/scala/fix/ComparisonToEmptyList.scala new file mode 100644 index 0000000..1333f5e --- /dev/null +++ b/rules/src/main/scala/fix/ComparisonToEmptyList.scala @@ -0,0 +1,41 @@ +/* +rule = ComparisonToEmptyList + */ +package fix + +import scalafix.lint.LintSeverity +import scalafix.v1._ + +import scala.meta._ + +class ComparisonToEmptyList extends SemanticRule("ComparisonToEmptyList") { + + private def diag(pos: Position) = Diagnostic( + "", + "Checks for code like `a == List()`, `a == Nil`, `a != List()` or `a != Nil`.", + pos, + "Prefer use of `isEmpty`, or `nonEmpty` instead of comparison to an empty List.", + LintSeverity.Info + ) + + override def fix(implicit doc: SemanticDocument): Patch = { + + def isEmptyList(term: Term) = term match { + // List() + case Term.Apply.After_4_6_0(Term.Name("List"), Term.ArgClause(Nil, _)) => true + // List.apply() + case Term.Apply.After_4_6_0(Term.Select(Term.Name("List"), Term.Name("apply")), Term.ArgClause(Nil, _)) => true + // List.empty + case Term.Select(Term.Name("List"), Term.Name("empty")) => true + // Nil + case Term.Name("Nil") => true + case _ => false + } + + doc.tree.collect { + // Corresponds to a == List() or List() == a, or any of the empty lists above. Also handles a != List() or List() != a, with the empty lists above too. + case Term.ApplyInfix.After_4_6_0(lhs, Term.Name("==" | "!="), _, Term.ArgClause(List(rhs), _)) if isEmptyList(lhs) || isEmptyList(rhs) => Patch.lint(diag(lhs.pos)) + }.asPatch + } + +} diff --git a/rules/src/main/scala/fix/ComparisonToEmptySet.scala b/rules/src/main/scala/fix/ComparisonToEmptySet.scala new file mode 100644 index 0000000..b612361 --- /dev/null +++ b/rules/src/main/scala/fix/ComparisonToEmptySet.scala @@ -0,0 +1,39 @@ +/* +rule = ComparisonToEmptySet + */ +package fix + +import scalafix.lint.LintSeverity +import scalafix.v1._ + +import scala.meta._ + +class ComparisonToEmptySet extends SemanticRule("ComparisonToEmptySet") { + + private def diag(pos: Position) = Diagnostic( + "", + "Checks for code like `a == Set()` or `a == Set.empty`.", + pos, + "Prefer use of `isEmpty` instead of comparison to an empty Set.", + LintSeverity.Info + ) + + override def fix(implicit doc: SemanticDocument): Patch = { + + def isEmptySet(term: Term) = term match { + // Set() + case Term.Apply.After_4_6_0(Term.Name("Set"), Term.ArgClause(Nil, _)) => true + // Set.apply() + case Term.Apply.After_4_6_0(Term.Select(Term.Name("Set"), Term.Name("apply")), Term.ArgClause(Nil, _)) => true + // Set.empty + case Term.Select(Term.Name("Set"), Term.Name("empty")) => true + case _ => false + } + + doc.tree.collect { + // Corresponds to a == Set() or Set() == a, or any of the empty sets above. Also handles a != Set() or Set() != a, with the empty sets above too. + case Term.ApplyInfix.After_4_6_0(lhs, Term.Name("==" | "!="), _, Term.ArgClause(List(rhs), _)) if isEmptySet(lhs) || isEmptySet(rhs) => Patch.lint(diag(lhs.pos)) + }.asPatch + } + +}