/**
   * If we are in a constructor, that is static compiled, but in a class, that is not, it may happen
   * that init code from object initializers, fields or properties is added into the constructor
   * code. The backend assumes a purely static contructor, so it may fail if it encounters dynamic
   * code here. Thus we make this kind of code fail
   */
  private void checkForConstructorWithCSButClassWithout(MethodNode node) {
    if (!(node instanceof ConstructorNode)) return;
    Object meta = node.getNodeMetaData(STATIC_COMPILE_NODE);
    if (!Boolean.TRUE.equals(meta)) return;
    ClassNode clz = typeCheckingContext.getEnclosingClassNode();
    meta = clz.getNodeMetaData(STATIC_COMPILE_NODE);
    if (Boolean.TRUE.equals(meta)) return;
    if (clz.getObjectInitializerStatements().isEmpty()
        && clz.getFields().isEmpty()
        && clz.getProperties().isEmpty()) {
      return;
    }

    addStaticTypeError(
        "Cannot statically compile constructor implicitly including non static elements from object initializers, properties or fields.",
        node);
  }
  protected ClassVisitor createClassVisitor() {
    CompilerConfiguration config = getConfiguration();
    int computeMaxStackAndFrames = ClassWriter.COMPUTE_MAXS;
    if (CompilerConfiguration.isPostJDK7(config.getTargetBytecode())
        || Boolean.TRUE.equals(config.getOptimizationOptions().get("indy"))) {
      computeMaxStackAndFrames += ClassWriter.COMPUTE_FRAMES;
    }
    return new ClassWriter(computeMaxStackAndFrames) {
      private ClassNode getClassNode(String name) {
        // try classes under compilation
        CompileUnit cu = getAST();
        ClassNode cn = cu.getClass(name);
        if (cn != null) return cn;
        // try inner classes
        cn = cu.getGeneratedInnerClass(name);
        if (cn != null) return cn;
        // try class loader classes
        try {
          cn = ClassHelper.make(cu.getClassLoader().loadClass(name, false, true), false);
        } catch (Exception e) {
          throw new GroovyBugError(e);
        }
        return cn;
      }

      private ClassNode getCommonSuperClassNode(ClassNode c, ClassNode d) {
        // adapted from ClassWriter code
        if (c.isDerivedFrom(d)) return d;
        if (d.isDerivedFrom(c)) return c;
        if (c.isInterface() || d.isInterface()) return ClassHelper.OBJECT_TYPE;
        do {
          c = c.getSuperClass();
        } while (c != null && !d.isDerivedFrom(c));
        if (c == null) return ClassHelper.OBJECT_TYPE;
        return c;
      }

      @Override
      protected String getCommonSuperClass(String arg1, String arg2) {
        ClassNode a = getClassNode(arg1.replace('/', '.'));
        ClassNode b = getClassNode(arg2.replace('/', '.'));
        return getCommonSuperClassNode(a, b).getName().replace('.', '/');
      }
    };
  }