All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sksamuel.scapegoat.inspections.collections.ExistsSimplifiableToContains.scala Maven / Gradle / Ivy

package com.sksamuel.scapegoat.inspections.collections

import com.sksamuel.scapegoat.{Inspection, InspectionContext, Inspector, Levels}

/**
 * @author Stephen Samuel
 *
 *         Inspired by Intellij
 */
class ExistsSimplifiableToContains
    extends Inspection(
      text = "Exists simplifiable to contains",
      defaultLevel = Levels.Info,
      description = "Checks if `exists()` can be simplified to `contains()`.",
      explanation = "`exists(x => x == y)` can be replaced with `contains(y)`."
    ) {

  def inspector(context: InspectionContext): Inspector =
    new Inspector(context) {
      override def postTyperTraverser =
        new context.Traverser {

          import context.global._

          private val Equals = TermName("$eq$eq")

          private def doesElementTypeMatch(container: Tree, value: Tree): Boolean = {
            val valueType = value.tpe.underlying.typeSymbol.tpe
            val traversableType = container.tpe.underlying.baseType(typeOf[Traversable[Any]].typeSymbol)
            traversableType.typeArgs.exists(t => valueType <:< t || valueType =:= t)
          }

          private def isContainsTraversable(tree: Tree): Boolean =
            // Traversable itself doesn't include a .contains() method
            isSet(tree) || isSeq(tree) || isList(tree) || isMap(tree)

          private def countUsagesOfAVariable(trees: List[Tree], symbolName: String): Int = {
            trees.map {
              case Select(Ident(TermName(termName)), _) if termName == symbolName =>
                1
              case tree =>
                countUsagesOfAVariable(tree.children, symbolName)
            }.sum
          }

          override def inspect(tree: Tree): Unit = {
            tree match {

              case Apply(
                    Select(lhs, TermName("exists")),
                    List(
                      Function(
                        List(ValDef(_, TermName(iterationVariable), _, _)),
                        subtree @ Apply(Select(_, Equals), List(x))
                      )
                    )
                  )
                  if isContainsTraversable(lhs) && doesElementTypeMatch(lhs, x)
                    && countUsagesOfAVariable(List(subtree), iterationVariable) == 1 =>
                context.warn(tree.pos, self, tree.toString.take(500))
              case _ => continue(tree)
            }
          }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy