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

com.avsystem.commons.analyzer.ValueEnumExhaustiveMatch.scala Maven / Gradle / Ivy

package com.avsystem.commons
package analyzer

import scala.collection.mutable
import scala.tools.nsc.Global

class ValueEnumExhaustiveMatch(g: Global) extends AnalyzerRule(g, "valueEnumExhaustiveMatch") {

  import global._

  lazy val valueEnumTpe: Type = classType("com.avsystem.commons.misc.ValueEnum")
  lazy val ExistentialType(_, TypeRef(miscPackageTpe, valueEnumCompanionSym, _)) =
    classType("com.avsystem.commons.misc.ValueEnumCompanion")

  def analyze(unit: CompilationUnit): Unit = if (valueEnumTpe != NoType) {
    unit.body.foreach(analyzeTree {
      case tree@Match(selector, cases) if selector.tpe <:< valueEnumTpe =>
        val expectedCompanionTpe = TypeRef(miscPackageTpe, valueEnumCompanionSym, List(selector.tpe))
        val companion = selector.tpe.typeSymbol.companion
        val companionTpe = companion.toType
        if (companionTpe <:< expectedCompanionTpe) {
          val unmatched = new mutable.LinkedHashSet[Symbol]
          companionTpe.decls.iterator
            .filter(s => s.isVal && s.isFinal && !s.isLazy && s.typeSignature <:< selector.tpe)
            .map(_.getterIn(companion)).filter(_.isPublic).foreach(unmatched.add)

          def findMatchedEnums(pattern: Tree): Unit = pattern match {
            case Bind(_, body) => findMatchedEnums(body)
            case Alternative(patterns) => patterns.foreach(findMatchedEnums)
            case Ident(termNames.WILDCARD) => unmatched.clear()
            case _: Ident | _: Select => unmatched.remove(pattern.symbol)
            case _: Literal =>
            case _ => unmatched.clear()
          }

          cases.iterator.foreach {
            case CaseDef(pattern, EmptyTree, _) => findMatchedEnums(pattern)
            case _ => unmatched.clear()
          }

          if (unmatched.nonEmpty) {
            val what =
              if (unmatched.size > 1) "inputs: " + unmatched.map(_.nameString).mkString(", ")
              else "input: " + unmatched.head.nameString
            report(tree.pos, "match may not be exhaustive.\nIt would fail on the following " + what)
          }
        }
    })
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy