import java.lang.Thread.holdsLock
import scala.collection.mutable.StringBuilder

object Util {
  def checkLocks(held: AnyRef*)(notHeld: AnyRef*) = {
    val sb = new StringBuilder
    for (lock <- held) {
      sb.append(if (holdsLock(lock)) '.' else '!')
    }
    print("%5s|" format sb)

    sb.clear()
    for (lock <- notHeld) {
      sb.append(if (holdsLock(lock)) '!' else '.')
    }
    print("%-15s " format sb)

    (held forall holdsLock) && !(notHeld exists holdsLock)
  }
}

class C1 {
  import Util._

  val lock = new AnyRef

  def f1 = synchronized { checkLocks(this)(this.getClass) }
  @inline final def fi = synchronized { checkLocks(this)(this.getClass) }
  val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, fv, fv.getClass) }
  def ff = {
    lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(ffv, ffv.getClass, lock.getClass) }
    ffv(this)
  }
  def fl = {
    lazy val flv = synchronized { checkLocks(this)(this.getClass) }
    flv
  }
  def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass) }

  def g1 = checkLocks()(this, this.getClass)
  @inline final def gi = checkLocks()(this, this.getClass)
  val gv: () => Boolean = () => checkLocks()(this, this.getClass, gv, gv.getClass)
  def gf = {
    lazy val gfv: AnyRef => Boolean = lock => checkLocks()(C1.this, gfv, gfv.getClass, lock, lock.getClass)
    gfv(this)
  }
  def gl = {
    lazy val glv = checkLocks()(this, this.getClass)
    glv
  }

  class C {
    def f1 = synchronized { checkLocks(this)(this.getClass, C1.this, C1.this.getClass) }
    @inline final def fi = synchronized { checkLocks(this)(this.getClass, C1.this, C1.this.getClass) }
    val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, C1.this, C1.this.getClass, fv, fv.getClass) }
    def ff = {
      lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(ffv, ffv.getClass, lock.getClass, C1.this, C1.this.getClass) }
      ffv(this)
    }
    def fl = {
      lazy val flv = synchronized { checkLocks(this)(this.getClass, C1.this, C1.this.getClass) }
      flv
    }
    def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass, C1.this, C1.this.getClass) }
    def fn = C1.this.synchronized { checkLocks(C1.this)(C1.this.getClass, this, this.getClass) }

    def g1 = checkLocks()(this, this.getClass, C1.this, C1.this.getClass)
    @inline final def gi = checkLocks()(this, this.getClass, C1.this, C1.this.getClass)
    val gv: () => Boolean = () => checkLocks()(this, this.getClass, C1.this, C1.this.getClass, gv, gv.getClass)
    def gf = {
      lazy val gfv: AnyRef => Boolean = lock => checkLocks()(gfv, gfv.getClass, lock, lock.getClass, C1.this, C1.this.getClass)
      gfv(this)
    }
    def gl = {
      lazy val glv = checkLocks()(this, this.getClass, C1.this, C1.this.getClass)
      glv
    }
  }
  val c = new C

  object O {
    def f1 = synchronized { checkLocks(this)(this.getClass, C1.this, C1.this.getClass) }
    @inline final def fi = synchronized { checkLocks(this)(this.getClass, C1.this, C1.this.getClass) }
    val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, fv, fv.getClass, C1.this, C1.this.getClass) }
    def ff = {
      lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(lock.getClass, ffv, ffv.getClass, C1.this, C1.this.getClass) }
      ffv(this)
    }
    def fl = {
      lazy val flv = synchronized { checkLocks(this)(this.getClass, C1.this, C1.this.getClass) }
      flv
    }
    def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass, C1.this, C1.this.getClass) }
    def fn = C1.this.synchronized { checkLocks(C1.this)(C1.this.getClass, this, this.getClass) }

    def g1 = checkLocks()(this, this.getClass, C1.this, C1.this.getClass)
    @inline final def gi = checkLocks()(this, this.getClass, C1.this, C1.this.getClass)
    val gv: () => Boolean = () => checkLocks()(this, this.getClass, gv, gv.getClass, C1.this, C1.this.getClass)
    def gf = {
      lazy val gfv: AnyRef => Boolean = lock => checkLocks()(lock, lock.getClass, gfv, gfv.getClass, C1.this, C1.this.getClass)
      gfv(this)
    }
    def gl = {
      lazy val glv = checkLocks()(this, this.getClass, C1.this, C1.this.getClass)
      glv
    }
  }
}

object O1 {
  import Util._

  val lock = new AnyRef

  def f1 = synchronized { checkLocks(this)(this.getClass) }
  @inline final def fi = synchronized { checkLocks(this)(this.getClass) }
  val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, fv, fv.getClass) }
  def ff = {
    lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(ffv, ffv.getClass, lock.getClass) }
    ffv(this)
  }
  def fl = {
    lazy val flv = synchronized { checkLocks(this)(this.getClass) }
    flv
  }
  def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass) }

  def g1 = checkLocks()(this, this.getClass)
  @inline final def gi = checkLocks()(this, this.getClass)
  val gv: () => Boolean = () => checkLocks()(this, this.getClass, gv, gv.getClass)
  def gf = {
    lazy val gfv: AnyRef => Boolean = lock => checkLocks()(gfv, gfv.getClass, lock, lock.getClass)
    gfv(this)
  }
  def gl = {
    lazy val glv = checkLocks()(this, this.getClass)
    glv
  }

  class C {
    def f1 = synchronized { checkLocks(this)(this.getClass, O1, O1.getClass) }
    @inline final def fi = synchronized { checkLocks(this)(this.getClass, O1, O1.getClass) }
    val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, O1, O1.getClass, fv, fv.getClass) }
    def ff = {
      lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(ffv, ffv.getClass, lock.getClass, O1, O1.getClass) }
      ffv(this)
    }
    def fl = {
      lazy val flv = synchronized { checkLocks(this)(this.getClass, O1, O1.getClass) }
      flv
    }
    def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass, O1, O1.getClass) }
    def fn = O1.synchronized { checkLocks(O1)(O1.getClass, this, this.getClass) }

    def g1 = checkLocks()(this, this.getClass, O1, O1.getClass)
    @inline final def gi = checkLocks()(this, this.getClass, O1, O1.getClass)
    val gv: () => Boolean = () => checkLocks()(this, this.getClass, O1, O1.getClass, gv, gv.getClass)
    def gf = {
      lazy val gfv: AnyRef => Boolean = lock => checkLocks()(gfv, gfv.getClass, lock, lock.getClass, O1, O1.getClass)
      gfv(this)
    }
    def gl = {
      lazy val glv = checkLocks()(this, this.getClass, O1, O1.getClass)
      glv
    }
  }
  val c = new C

  object O {
    def f1 = synchronized { checkLocks(this)(this.getClass, O1, O1.getClass) }
    @inline final def fi = synchronized { checkLocks(this)(this.getClass, O1, O1.getClass) }
    val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, fv, fv.getClass, O1, O1.getClass) }
    def ff = {
      lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(lock.getClass, ffv, ffv.getClass, O1, O1.getClass) }
      ffv(this)
    }
    def fl = {
      lazy val flv = synchronized { checkLocks(this)(this.getClass, O1, O1.getClass) }
      flv
    }
    def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass, O1, O1.getClass) }
    def fn = O1.synchronized { checkLocks(O1)(O1.getClass, this, this.getClass) }

    def g1 = checkLocks()(this, this.getClass, O1, O1.getClass)
    @inline final def gi = checkLocks()(this, this.getClass, O1, O1.getClass)
    val gv: () => Boolean = () => checkLocks()(this, this.getClass, gv, gv.getClass, O1, O1.getClass)
    def gf = {
      lazy val gfv: AnyRef => Boolean = lock => checkLocks()(lock, lock.getClass, gfv, gfv.getClass, O1, O1.getClass)
      gfv(this)
    }
    def gl = {
      lazy val glv = checkLocks()(this, this.getClass, O1, O1.getClass)
      glv
    }
  }
}

trait T {
  import Util._

  val Tclass = Class.forName("T$class")

  val lock = new AnyRef

  def f1 = synchronized { checkLocks(this)(this.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }
  @inline final def fi = synchronized { checkLocks(this)(this.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }
  val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, fv, fv.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }
  def ff = {
    lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(ffv, ffv.getClass, lock.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }
    ffv(this)
  }
  def fl = {
    lazy val flv = synchronized { checkLocks(this)(this.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }
    flv
  }
  def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }

  def g1 = checkLocks()(this, this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
  @inline final def gi = checkLocks()(this, this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
  val gv: () => Boolean = () => checkLocks()(this, this.getClass, gv, gv.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
  def gf = {
    lazy val gfv: AnyRef => Boolean = lock => checkLocks()(gfv, gfv.getClass, lock, lock.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
    gfv(this)
  }
  def gl = {
    lazy val glv = checkLocks()(this, this.getClass, classOf[T], Tclass, classOf[C2], O2.getClass)
    glv
  }

  class C {
    def f1 = synchronized { checkLocks(this)(this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    @inline final def fi = synchronized { checkLocks(this)(this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, T.this, T.this.getClass, fv, fv.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    def ff = {
      lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(ffv, ffv.getClass, lock.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
      ffv(this)
    }
    def fl = {
      lazy val flv = synchronized { checkLocks(this)(this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
      flv
    }
    def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    def fn = T.this.synchronized { checkLocks(T.this)(T.this.getClass, this, this.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }

    def g1 = checkLocks()(this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
    @inline final def gi = checkLocks()(this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
    val gv: () => Boolean = () => checkLocks()(this, this.getClass, T.this, T.this.getClass, gv, gv.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
    def gf = {
      lazy val gfv: AnyRef => Boolean = lock => checkLocks()(gfv, gfv.getClass, lock, lock.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
      gfv(this)
    }
    def gl = {
      lazy val glv = checkLocks()(this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
      glv
    }
  }
  val c = new C

  object O {
    def f1 = synchronized { checkLocks(this)(this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    @inline final def fi = synchronized { checkLocks(this)(this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    val fv: () => Boolean = () => synchronized { checkLocks(this)(this.getClass, fv, fv.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    def ff = {
      lazy val ffv: AnyRef => Boolean = lock => synchronized { checkLocks(lock)(lock.getClass, ffv, ffv.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
      ffv(this)
    }
    def fl = {
      lazy val flv = synchronized { checkLocks(this)(this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
      flv
    }
    def fo = lock.synchronized { checkLocks(lock)(lock.getClass, this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass) }
    def fn = T.this.synchronized { checkLocks(T.this)(T.this.getClass, this, this.getClass, classOf[T], Tclass, classOf[C2], O2.getClass) }

    def g1 = checkLocks()(this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
    @inline final def gi = checkLocks()(this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
    val gv: () => Boolean = () => checkLocks()(this, this.getClass, gv, gv.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
    def gf = {
      lazy val gfv: AnyRef => Boolean = lock => checkLocks()(lock, lock.getClass, gfv, gfv.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
      gfv(this)
    }
    def gl = {
      lazy val glv = checkLocks()(this, this.getClass, T.this, T.this.getClass, classOf[T], Tclass, classOf[C2], O2, O2.getClass)
      glv
    }
  }
}

class C2 extends T
object O2 extends T

object Test extends App {
  def check(name: String, result: Boolean) {
    println("%-10s %s" format (name +":", if (result) "OK" else "FAILED"))
  }

  val c1 = new C1
  check("c1.f1",   c1.f1)
  check("c1.fi",   c1.fi)
  check("c1.fv",   c1.fv())
  check("c1.ff",   c1.ff)
  check("c1.fl",   c1.fl)
  check("c1.fo",   c1.fo)
  check("c1.g1",   c1.g1)
  check("c1.gi",   c1.gi)
  check("c1.gv",   c1.gv())
  check("c1.gf",   c1.gf)
//  check("c1.gl",   c1.gl)   // FIXME *.gl are failing because of the issue described in SUGGEST-11

  check("c1.c.f1",   c1.c.f1)
  check("c1.c.fi",   c1.c.fi)
  check("c1.c.fv",   c1.c.fv())
  check("c1.c.ff",   c1.c.ff)
  check("c1.c.fl",   c1.c.fl)
  check("c1.c.fo",   c1.c.fo)
  check("c1.c.fn",   c1.c.fn)
  check("c1.c.g1",   c1.c.g1)
  check("c1.c.gi",   c1.c.gi)
  check("c1.c.gv",   c1.c.gv())
  check("c1.c.gf",   c1.c.gf)
//  check("c1.c.gl",   c1.c.gl)

  check("c1.O.f1",   c1.O.f1)
  check("c1.O.fi",   c1.O.fi)
  check("c1.O.fv",   c1.O.fv())
  check("c1.O.ff",   c1.O.ff)
  check("c1.O.fl",   c1.O.fl)
  check("c1.O.fo",   c1.O.fo)
  check("c1.O.fn",   c1.O.fn)
  check("c1.O.g1",   c1.O.g1)
  check("c1.O.gi",   c1.O.gi)
  check("c1.O.gv",   c1.O.gv())
  check("c1.O.gf",   c1.O.gf)
//  check("c1.O.gl",   c1.O.gl)

  check("O1.f1",   O1.f1)
  check("O1.fi",   O1.fi)
  check("O1.fv",   O1.fv())
  check("O1.ff",   O1.ff)
  check("O1.fl",   O1.fl)
  check("O1.fo",   O1.fo)
  check("O1.g1",   O1.g1)
  check("O1.gi",   O1.gi)
  check("O1.gv",   O1.gv())
  check("O1.gf",   O1.gf)
//  check("O1.gl",   O1.gl)

  check("O1.c.f1",   O1.c.f1)
  check("O1.c.fi",   O1.c.fi)
  check("O1.c.fv",   O1.c.fv())
  check("O1.c.ff",   O1.c.ff)
  check("O1.c.fl",   O1.c.fl)
  check("O1.c.fo",   O1.c.fo)
  check("O1.c.fn",   O1.c.fn)
  check("O1.c.g1",   O1.c.g1)
  check("O1.c.gi",   O1.c.gi)
  check("O1.c.gv",   O1.c.gv())
  check("O1.c.gf",   O1.c.gf)
//  check("O1.c.gl",   O1.c.gl)

  check("O1.O.f1",   O1.O.f1)
  check("O1.O.fi",   O1.O.fi)
  check("O1.O.fv",   O1.O.fv())
  check("O1.O.ff",   O1.O.ff)
  check("O1.O.fl",   O1.O.fl)
  check("O1.O.fo",   O1.O.fo)
  check("O1.O.fn",   O1.O.fn)
  check("O1.O.g1",   O1.O.g1)
  check("O1.O.gi",   O1.O.gi)
  check("O1.O.gv",   O1.O.gv())
  check("O1.O.gf",   O1.O.gf)
//  check("O1.O.gl",   O1.O.gl)

  val c2 = new C2
  check("c2.f1",   c2.f1)
  check("c2.fi",   c2.fi)
  check("c2.fv",   c2.fv())
  check("c2.ff",   c2.ff)
  check("c2.fl",   c2.fl)
  check("c2.fo",   c2.fo)
  check("c2.g1",   c2.g1)
  check("c2.gi",   c2.gi)
  check("c2.gv",   c2.gv())
  check("c2.gf",   c2.gf)
//  check("c2.gl",   c2.gl)

  check("c2.c.f1",   c2.c.f1)
  check("c2.c.fi",   c2.c.fi)
  check("c2.c.fv",   c2.c.fv())
  check("c2.c.ff",   c2.c.ff)
  check("c2.c.fl",   c2.c.fl)
  check("c2.c.fo",   c2.c.fo)
  check("c2.c.fn",   c2.c.fn)
  check("c2.c.g1",   c2.c.g1)
  check("c2.c.gi",   c2.c.gi)
  check("c2.c.gv",   c2.c.gv())
  check("c2.c.gf",   c2.c.gf)
//  check("c2.c.gl",   c2.c.gl)

  check("c2.O.f1",   c2.O.f1)
  check("c2.O.fi",   c2.O.fi)
  check("c2.O.fv",   c2.O.fv())
  check("c2.O.ff",   c2.O.ff)
  check("c2.O.fl",   c2.O.fl)
  check("c2.O.fo",   c2.O.fo)
  check("c2.O.fn",   c2.O.fn)
  check("c2.O.g1",   c2.O.g1)
  check("c2.O.gi",   c2.O.gi)
  check("c2.O.gv",   c2.O.gv())
  check("c2.O.gf",   c2.O.gf)
//  check("c2.O.gl",   c2.O.gl)

  check("O2.f1",   O2.f1)
  check("O2.fi",   O2.fi)
  check("O2.fv",   O2.fv())
  check("O2.ff",   O2.ff)
  check("O2.fl",   O2.fl)
  check("O2.fo",   O2.fo)
  check("O2.g1",   O2.g1)
  check("O2.gi",   O2.gi)
  check("O2.gv",   O2.gv())
  check("O2.gf",   O2.gf)
//  check("O2.gl",   O2.gl)

  check("O2.c.f1",   O2.c.f1)
  check("O2.c.fi",   O2.c.fi)
  check("O2.c.fv",   O2.c.fv())
  check("O2.c.ff",   O2.c.ff)
  check("O2.c.fl",   O2.c.fl)
  check("O2.c.fo",   O2.c.fo)
  check("O2.c.fn",   O2.c.fn)
  check("O2.c.g1",   O2.c.g1)
  check("O2.c.gi",   O2.c.gi)
  check("O2.c.gv",   O2.c.gv())
  check("O2.c.gf",   O2.c.gf)
//  check("O2.c.gl",   O2.c.gl)

  check("O2.O.f1",   O2.O.f1)
  check("O2.O.fi",   O2.O.fi)
  check("O2.O.fv",   O2.O.fv())
  check("O2.O.ff",   O2.O.ff)
  check("O2.O.fl",   O2.O.fl)
  check("O2.O.fo",   O2.O.fo)
  check("O2.O.fn",   O2.O.fn)
  check("O2.O.g1",   O2.O.g1)
  check("O2.O.gi",   O2.O.gi)
  check("O2.O.gv",   O2.O.gv())
  check("O2.O.gf",   O2.O.gf)
//  check("O2.O.gl",   O2.O.gl)
}