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,initandlastmethods,
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#lastOptionrespectively,
to explicitly handle both populated and empty GenTraversableLikes.
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,toFloatandtoDoublemethods,
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,maxByandminBymethods,
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.