Some extra WartRemover warts that aren't available out of the box.
ExtraWarts version | WartRemover version | Scala version | sbt version | Supported |
---|---|---|---|---|
1.0.3 | 2.2.1 | 2.11.11, 2.12.3 | 0.13.x, 1.0.x | |
0.3.0 | 2.1.1 | 2.11.8, 2.12.2 | 0.13.x | No |
-
Setup WartRemover.
-
Add the following to your
plugins.sbt
:addSbtPlugin("org.danielnixon" % "sbt-extrawarts" % "1.0.3")
-
Add the following to your
build.sbt
:wartremoverWarnings ++= Seq( ExtraWart.EnumerationPartial, ExtraWart.FutureObject, ExtraWart.GenMapLikePartial, ExtraWart.GenTraversableLikeOps, ExtraWart.GenTraversableOnceOps, ExtraWart.ScalaGlobalExecutionContext, ExtraWart.StringOpsPartial, ExtraWart.ThrowablePartial, ExtraWart.TraversableOnceOps, ExtraWart.UnsafeContains)
scala.Enumeration#withName
is disabled because is will throw a NoSuchElementException
if there is no value matching the specified name. You can wrap it in an implicit that might look like this:
implicit class EnumerationWrapper[A <: Enumeration](val enum: A) extends AnyVal {
@SuppressWarnings(Array("org.danielnixon.extrawarts.EnumerationPartial"))
def withNameOpt(s: String): Option[A#Value] = {
catching[A#Value](classOf[NoSuchElementException]) opt enum.withName(s)
}
}
scala.concurrent.Future
has a reduce
method that can throw NoSuchElementException
if the collection is empty. Use Future#fold
instead.
scala.collection.GenMapLike
has an apply
method that can throw NoSuchElementException
if there is no mapping for the given key. Use GenMapLike#get
instead.
WartRemover's TraversableOps wart only applies to scala.collection.Traversable
. The GenTraversableLikeOps
wart extends it to everything that implements scala.collection.GenTraversableLike
.
scala.collection.GenTraversableLike
has:
head
,tail
,init
andlast
methods,
all of which will throw if the list is empty. The program should be refactored to use:
GenTraversableLike#headOption
,GenTraversableLike#drop(1)
,GenTraversableLike#dropRight(1)
andGenTraversableLike#lastOption
respectively,
to explicitly handle both populated and empty GenTraversableLike
s.
Scala's global execution context scala.concurrent.ExecutionContext#global
is disabled. Declare a dependency on an ExecutionContext
instead. See MUST NOT hardcode the thread-pool / execution context.
scala.collection.immutable.StringOps
has
toBoolean
,toByte
,toShort
,toInt
,toLong
,toFloat
andtoDouble
methods,
all of which will throw NumberFormatException
(or IllegalArgumentException
in the case of toBoolean
) if the string cannot be parsed.
You can hide these unsafe StringOps
methods with an implicit class that might look something like this:
implicit class StringWrapper(val value: String) extends AnyVal {
import scala.util.control.Exception.catching
@SuppressWarnings(Array("org.danielnixon.extrawarts.StringOpsPartial"))
def toIntOpt: Option[Int] = catching[Int](classOf[NumberFormatException]) opt value.toInt
}
java.lang.Throwable#getCause
is disabled because it can return null. You can wrap it in an implicit that might look like this:
implicit class ThrowableWrapper(val t: Throwable) extends AnyVal {
@SuppressWarnings(Array("org.danielnixon.extrawarts.ThrowablePartial"))
def cause: Option[Throwable] = Option(t.getCause)
}
scala.collection.TraversableOnce
has a reduceLeft
method that will throw if the collection is empty. Use TraversableOnce#reduceLeftOption
or TraversableOnce#foldLeft
instead.
scala.collection.TraversableOnce
has
max
,min
,maxBy
andminBy
methods,
all of which will throw UnsupportedOperationException
if the collection is empty. You can wrap these unsafe methods in an implicit class that might look something like this:
implicit class TraversableOnceWrapper[A](val traversable: TraversableOnce[A]) extends AnyVal {
@SuppressWarnings(Array("org.danielnixon.extrawarts.TraversableOnceOps"))
def maxOpt[B >: A](implicit cmp: Ordering[B]): Option[A] = {
if (traversable.isEmpty) None else Some(traversable.max(cmp))
}
}
scala.collection.SeqLike#contains
is based on universal equality (seq.contains(elem)
is equivalent to seq.exists(_ == elem)
) so it is disabled.
If you use Scalaz, you can replace it with something like this:
import scalaz._
import Scalaz._
implicit class SeqLikeWrapper[A](val seq: SeqLike[A, _]) extends AnyVal {
def containsSafe(elem: A)(implicit ev: Equal[A]): Boolean = {
seq.exists(x => elem === x)
}
}
If you use Cats, you can replace it with something like this:
import cats.Eq
import cats.implicits._
implicit class SeqLikeWrapper[A](val seq: SeqLike[A, _]) extends AnyVal {
def containsSafe(elem: A)(implicit ev: Eq[A]): Boolean = {
seq.exists(x => elem === x)
}
}
Or simply (if you're willing to tolerate the universal equality):
implicit class SeqLikeWrapper[A](val seq: SeqLike[A, _]) extends AnyVal {
@SuppressWarnings(Array("org.danielnixon.extrawarts.UnsafeContains"))
def containsSafe(elem: A): Boolean = seq.contains(elem)
}
- PlayWarts: WartRemover warts for Play Framework.
- SlickWarts: WartRemover warts for Slick.
- Scala.js Warts: WartRemover warts for Scala.js.