Search code examples
scalaannotationsscala-macros

How to manipulate modifiers in annotation macros


How to manipulate modifiers? For example, I want to exclude Flaga.CASE in ClassDef modifiers. However, following causes a compile error.

case q"$mods class $name [..$tp](..$vals) extends ..$exts { ..$defs }" if mods.hasFlag(Flag.CASE) =>
       val m = mods - Flag.CASE
       q"$m class $name [..$tp](..$vals) { ..$defs }"

error is

[error] ...: value - is not a member of c.universe.Modifiers
[error]         val m = mods - Flag.CASE
[error]                      ^
[error] one error found

Ok, Modifiers api does not have - to exclude specified element (I expected this method works like Set's - if exists).

My question is, as I mentioned above, is there a method to manipulate Modifiers?


Solution

  • Try

    import c.universe._
    
    implicit class ModifiersOps(left: Modifiers) {
      def & (right: FlagSet): Modifiers = left match {
        case Modifiers(flags, privateWithin, annots) => Modifiers(flags & right, privateWithin, annots)
      }
    }
    
    implicit class FlagSetOps(left: FlagSet) {
      def & (right: FlagSet): FlagSet = (left.asInstanceOf[Long] & right.asInstanceOf[Long]).asInstanceOf[FlagSet]
      def unary_~ : FlagSet = (~ left.asInstanceOf[Long]).asInstanceOf[FlagSet]
    }
    
    annottees.head match {
      case q"${mods: Modifiers} class $name [..$tp](..$vals) extends ..$exts { ..$defs }" if mods.hasFlag(Flag.CASE) =>
        val m = mods & ~Flag.CASE
        q"$m class $name [..$tp](..$vals) { ..$defs }"
    }