diff --git a/src/main/scala/com/sksamuel/scapegoat/ScapegoatConfig.scala b/src/main/scala/com/sksamuel/scapegoat/ScapegoatConfig.scala index 4f0ddcdb..a09efad6 100644 --- a/src/main/scala/com/sksamuel/scapegoat/ScapegoatConfig.scala +++ b/src/main/scala/com/sksamuel/scapegoat/ScapegoatConfig.scala @@ -39,6 +39,7 @@ object ScapegoatConfig extends App { new CatchFatal, new CatchThrowable, new ClassNames, + new CollectionIndexOnNonIndexedSeq, new CollectionNamingConfusion, new CollectionNegativeIndex, new CollectionPromotionToAny, diff --git a/src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeq.scala b/src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeq.scala new file mode 100644 index 00000000..9b272794 --- /dev/null +++ b/src/main/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeq.scala @@ -0,0 +1,29 @@ +package com.sksamuel.scapegoat.inspections.collections + +import com.sksamuel.scapegoat._ + +/** @author Josh Rosen */ +class CollectionIndexOnNonIndexedSeq extends Inspection { + + def inspector(context: InspectionContext): Inspector = new Inspector(context) { + override def postTyperTraverser = Some apply new context.Traverser { + + import context.global._ + + private def isSeq(t: Tree) = t.tpe <:< typeOf[Seq[_]] + private def isIndexedSeq(t: Tree) = t.tpe <:< typeOf[IndexedSeq[_]] + + override def inspect(tree: Tree): Unit = { + tree match { + case Apply(Select(lhs, TermName("apply")), List(_)) if isSeq(lhs) && !isIndexedSeq(lhs) => + context.warn("Seq.apply() on a non-IndexedSeq may cause performance problems", + tree.pos, + Levels.Warning, + tree.toString().take(100), + CollectionIndexOnNonIndexedSeq.this) + case _ => continue(tree) + } + } + } + } +} diff --git a/src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeqTest.scala b/src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeqTest.scala new file mode 100644 index 00000000..3d12487f --- /dev/null +++ b/src/test/scala/com/sksamuel/scapegoat/inspections/collections/CollectionIndexOnNonIndexedSeqTest.scala @@ -0,0 +1,34 @@ +package com.sksamuel.scapegoat.inspections.collections + +import com.sksamuel.scapegoat.PluginRunner +import org.scalatest.{ FreeSpec, Matchers, OneInstancePerTest } + +/** @author Josh Rosen */ +class CollectionIndexOnNonIndexedSeqTest extends FreeSpec with Matchers with PluginRunner with OneInstancePerTest { + + override val inspections = Seq(new CollectionIndexOnNonIndexedSeq) + + "collection index on non indexed Seq" - { + "should report warning" in { + val code = """object Test { + List(1,2,3)(1) + Seq(1,2,3)(2) + val s: Seq[Int] = Array(1,2,3) + s(2) + } """.stripMargin + + compileCodeSnippet(code) + compiler.scapegoat.feedback.warnings.size shouldBe 3 + } + "should not report warning" in { + val code = """object Test { + Array(1,2,3)(1) + IndexedSeq(1,2,3)(2) + Vector(1,2,3)(2) + } """.stripMargin + + compileCodeSnippet(code) + compiler.scapegoat.feedback.warnings.size shouldBe 0 + } + } +}