Skip to content

Commit

Permalink
Added UnreachableCatch
Browse files Browse the repository at this point in the history
  • Loading branch information
t1b00 committed Aug 16, 2024
1 parent e56e837 commit 42cfc3d
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 1 deletion.
46 changes: 46 additions & 0 deletions input/src/main/scala/fix/UnreachableCatch.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
rule = UnreachableCatch
*/
package fix

import scala.annotation.nowarn

object UnreachableCatch {

@nowarn // Some unreachable warning may appear thanks to Scala built-in warnings.
// Since we are testing the rule, we can ignore them.
def test(): Unit = {
try {
} catch {
case _ : Throwable => // scalafix: ok;
case e : Exception => // assert: UnreachableCatch
}

// Test case 2 with unreachability due to guard
try {
} catch {
case e: RuntimeException => // scalafix: ok;
case e: RuntimeException if e.getMessage.contains("foo") => // assert: UnreachableCatch
}

try {
} catch {
case e : RuntimeException => // scalafix: ok;
case f : Exception => // scalafix: ok;
case x : Throwable => // scalafix: ok;
}

try {
} catch {
case e: RuntimeException if e.getMessage.contains("foo") => // scalafix: ok;
case e: RuntimeException => // scalafix: ok;
}

try {
} catch {
case e: RuntimeException if e.getMessage.contains("foo") => // scalafix: ok;
case e: RuntimeException if e.getMessage.contains("bar") => // scalafix: ok;
}
}

}
3 changes: 2 additions & 1 deletion rules/src/main/resources/META-INF/services/scalafix.v1.Rule
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ fix.NullAssignment
fix.RepeatedCaseBody
fix.RepeatedIfElseBody
fix.SwallowedException
fix.UnnecessaryConversion
fix.UnnecessaryConversion
fix.UnreachableCatch
44 changes: 44 additions & 0 deletions rules/src/main/scala/fix/UnreachableCatch.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
rule = UnreachableCatch
*/
package fix

import scalafix.lint.LintSeverity
import scalafix.v1._

import scala.collection.mutable
import scala.meta._

class UnreachableCatch extends SemanticRule("UnreachableCatch") {

private def diag(pos: Position) = Diagnostic(
"",
"Checks for catch clauses that cannot be reached.",
pos,
"One or more cases are unreachable.",
LintSeverity.Warning
)


override def fix(implicit doc: SemanticDocument): Patch = {

doc.tree.collect {
case Term.Try(_, cases, _) =>
val types = mutable.HashSet[String]()
cases.collect {
case c @ Case(Pat.Typed(_, tpe), guard, _) =>
if(types.exists(t => Util.inheritsFrom(tpe.symbol, t))) Patch.lint(diag(c.pos))
else {
tpe.symbol.info.foreach(_.signature match {
case TypeSignature(_, _, TypeRef(_, symbol, _)) if guard.isEmpty => types.add(symbol.value) // Extract upperbound symbol of type
// We only add it if there is no guard because if we have twice the same type they trivially inherit from each other.
// By adding only if there is no guard, we will flag later ones with guards as unreachable, because they will be. See test case 2
case _ => ()
})
Patch.empty
}
case _ => Patch.empty
}
}.flatten.asPatch
}
}

0 comments on commit 42cfc3d

Please sign in to comment.