private int getSuperInterfaceCount(ClassNode element) {
   int count = 1;
   ClassNode[] interfaces = element.getInterfaces();
   for (ClassNode anInterface : interfaces) {
     count = Math.max(count, getSuperInterfaceCount(anInterface) + 1);
   }
   return count;
 }
 public static Set<ClassNode> getInterfacesAndSuperInterfaces(ClassNode type) {
   Set<ClassNode> res = new HashSet<ClassNode>();
   if (type.isInterface()) {
     res.add(type);
     return res;
   }
   ClassNode next = type;
   while (next != null) {
     Collections.addAll(res, next.getInterfaces());
     next = next.getSuperClass();
   }
   return res;
 }
 public static String getGenericsSignature(ClassNode node) {
   if (!usesGenericsInClassSignature(node)) return null;
   GenericsType[] genericsTypes = node.getGenericsTypes();
   StringBuffer ret = new StringBuffer(100);
   getGenericsTypeSpec(ret, genericsTypes);
   GenericsType extendsPart = new GenericsType(node.getUnresolvedSuperClass(false));
   writeGenericsBounds(ret, extendsPart, true);
   ClassNode[] interfaces = node.getInterfaces();
   for (int i = 0; i < interfaces.length; i++) {
     GenericsType interfacePart = new GenericsType(interfaces[i]);
     writeGenericsBounds(ret, interfacePart, false);
   }
   return ret.toString();
 }
  private static boolean usesGenericsInClassSignature(ClassNode node) {
    if (!node.isUsingGenerics()) return false;
    if (hasGenerics(node)) return true;
    ClassNode sclass = node.getUnresolvedSuperClass(false);
    if (sclass.isUsingGenerics()) return true;
    ClassNode[] interfaces = node.getInterfaces();
    if (interfaces != null) {
      for (int i = 0; i < interfaces.length; i++) {
        if (interfaces[i].isUsingGenerics()) return true;
      }
    }

    return false;
  }
  /**
   * Interface class nodes retrieved from {@link org.codehaus.groovy.ast.ClassNode#getInterfaces()}
   * or {@link org.codehaus.groovy.ast.ClassNode#getAllInterfaces()} are returned with generic type
   * arguments. This method allows returning a parameterized interface given the parameterized class
   * node which implements this interface.
   *
   * @param hint the class node where generics types are parameterized
   * @param target the interface we want to parameterize generics types
   * @return a parameterized interface class node
   */
  public static ClassNode parameterizeType(final ClassNode hint, final ClassNode target) {
    ClassNode interfaceFromClassNode = null;
    if (hint.equals(target)) interfaceFromClassNode = hint;
    if (ClassHelper.OBJECT_TYPE.equals(target)
        && target.isUsingGenerics()
        && target.getGenericsTypes() != null
        && target.getGenericsTypes()[0].isPlaceholder()) {
      // Object<T>
      return ClassHelper.getWrapper(hint);
    }
    if (interfaceFromClassNode == null) {
      ClassNode[] interfaces = hint.getInterfaces();
      for (ClassNode node : interfaces) {
        if (node.equals(target)) {
          interfaceFromClassNode = node;
          break;
        } else if (node.implementsInterface(target)) {
          // ex: classNode = LinkedList<A> , node=List<E> , anInterface = Iterable<T>
          return parameterizeType(parameterizeType(hint, node), target);
        }
      }
    }
    if (interfaceFromClassNode == null && hint.getUnresolvedSuperClass() != null) {
      return parameterizeType(hint.getUnresolvedSuperClass(), target);
    }
    if (interfaceFromClassNode == null) {

      //            return target;
      interfaceFromClassNode = hint;
    }
    Map<String, GenericsType> parameters = new HashMap<String, GenericsType>();
    extractPlaceholders(hint, parameters);
    ClassNode node = target.getPlainNodeReference();
    GenericsType[] interfaceGTs = interfaceFromClassNode.getGenericsTypes();
    if (interfaceGTs == null) return target;
    GenericsType[] types = new GenericsType[interfaceGTs.length];
    for (int i = 0; i < interfaceGTs.length; i++) {
      GenericsType interfaceGT = interfaceGTs[i];
      types[i] = interfaceGT;
      if (interfaceGT.isPlaceholder()) {
        String name = interfaceGT.getName();
        if (parameters.containsKey(name)) {
          types[i] = parameters.get(name);
        }
      }
    }
    node.setGenericsTypes(types);
    return node;
  }
 private void checkImplementsAndExtends(ClassNode node) {
   ClassNode cn = node.getSuperClass();
   if (cn.isInterface() && !node.isInterface()) {
     addError(
         "You are not allowed to extend the " + getDescription(cn) + ", use implements instead.",
         node);
   }
   for (ClassNode anInterface : node.getInterfaces()) {
     cn = anInterface;
     if (!cn.isInterface()) {
       addError(
           "You are not allowed to implement the " + getDescription(cn) + ", use extends instead.",
           node);
     }
   }
 }
  // GroovyClassVisitor interface
  // -------------------------------------------------------------------------
  public void visitClass(ClassNode classNode) {
    try {
      this.classNode = classNode;
      this.internalClassName = BytecodeHelper.getClassInternalName(classNode);

      // System.out.println("Generating class: " + classNode.getName());

      this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());

      cv.visit(
          Opcodes.V1_3,
          classNode.getModifiers(),
          internalClassName,
          (String) null,
          internalBaseClassName,
          BytecodeHelper.getClassInternalNames(classNode.getInterfaces()));

      classNode.visitContents(this);

      for (Iterator iter = innerClasses.iterator(); iter.hasNext(); ) {
        ClassNode innerClass = (ClassNode) iter.next();
        ClassNode innerClassType = innerClass;
        String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassType);
        String outerClassName = internalClassName; // default for inner classes
        MethodNode enclosingMethod = innerClass.getEnclosingMethod();
        if (enclosingMethod != null) {
          // local inner classes do not specify the outer class name
          outerClassName = null;
        }
        cv.visitInnerClass(
            innerClassInternalName,
            outerClassName,
            innerClassType.getName(),
            innerClass.getModifiers());
      }
      cv.visitEnd();
    } catch (GroovyRuntimeException e) {
      e.setModule(classNode.getModule());
      throw e;
    }
  }
  private void printClassContents(PrintWriter out, ClassNode classNode)
      throws FileNotFoundException {
    if (classNode instanceof InnerClassNode && ((InnerClassNode) classNode).isAnonymous()) {
      // if it is an anonymous inner class, don't generate the stub code for it.
      return;
    }
    try {
      Verifier verifier =
          new Verifier() {
            public void addCovariantMethods(ClassNode cn) {}

            protected void addTimeStamp(ClassNode node) {}

            protected void addInitialization(ClassNode node) {}

            protected void addPropertyMethod(MethodNode method) {
              doAddMethod(method);
            }

            protected void addReturnIfNeeded(MethodNode node) {}

            protected void addMethod(
                ClassNode node,
                boolean shouldBeSynthetic,
                String name,
                int modifiers,
                ClassNode returnType,
                Parameter[] parameters,
                ClassNode[] exceptions,
                Statement code) {
              doAddMethod(
                  new MethodNode(name, modifiers, returnType, parameters, exceptions, code));
            }

            protected void addConstructor(
                Parameter[] newParams, ConstructorNode ctor, Statement code, ClassNode node) {
              if (code instanceof ExpressionStatement) { // GROOVY-4508
                Statement temp = code;
                code = new BlockStatement();
                ((BlockStatement) code).addStatement(temp);
              }
              ConstructorNode ctrNode =
                  new ConstructorNode(ctor.getModifiers(), newParams, ctor.getExceptions(), code);
              ctrNode.setDeclaringClass(node);
              constructors.add(ctrNode);
            }

            protected void addDefaultParameters(DefaultArgsAction action, MethodNode method) {
              final Parameter[] parameters = method.getParameters();
              final Expression[] saved = new Expression[parameters.length];
              for (int i = 0; i < parameters.length; i++) {
                if (parameters[i].hasInitialExpression())
                  saved[i] = parameters[i].getInitialExpression();
              }
              super.addDefaultParameters(action, method);
              for (int i = 0; i < parameters.length; i++) {
                if (saved[i] != null) parameters[i].setInitialExpression(saved[i]);
              }
            }

            private void doAddMethod(MethodNode method) {
              String sig = method.getTypeDescriptor();

              if (propertyMethodsWithSigs.containsKey(sig)) return;

              propertyMethods.add(method);
              propertyMethodsWithSigs.put(sig, method);
            }

            @Override
            protected void addDefaultConstructor(ClassNode node) {
              // not required for stub generation
            }
          };
      verifier.visitClass(classNode);
      currentModule = classNode.getModule();

      boolean isInterface = classNode.isInterface();
      boolean isEnum = (classNode.getModifiers() & Opcodes.ACC_ENUM) != 0;
      boolean isAnnotationDefinition = classNode.isAnnotationDefinition();
      printAnnotations(out, classNode);
      printModifiers(
          out,
          classNode.getModifiers()
              & ~(isInterface ? Opcodes.ACC_ABSTRACT : 0)
              & ~(isEnum ? Opcodes.ACC_FINAL : 0));

      if (isInterface) {
        if (isAnnotationDefinition) {
          out.print("@");
        }
        out.print("interface ");
      } else if (isEnum) {
        out.print("enum ");
      } else {
        out.print("class ");
      }

      String className = classNode.getNameWithoutPackage();
      if (classNode instanceof InnerClassNode)
        className = className.substring(className.lastIndexOf("$") + 1);
      out.println(className);
      printGenericsBounds(out, classNode, true);

      ClassNode superClass = classNode.getUnresolvedSuperClass(false);

      if (!isInterface && !isEnum) {
        out.print("  extends ");
        printType(out, superClass);
      }

      ClassNode[] interfaces = classNode.getInterfaces();
      if (interfaces != null && interfaces.length > 0 && !isAnnotationDefinition) {
        if (isInterface) {
          out.println("  extends");
        } else {
          out.println("  implements");
        }
        for (int i = 0; i < interfaces.length - 1; ++i) {
          out.print("    ");
          printType(out, interfaces[i]);
          out.print(",");
        }
        out.print("    ");
        printType(out, interfaces[interfaces.length - 1]);
      }
      out.println(" {");

      printFields(out, classNode);
      printMethods(out, classNode, isEnum);

      for (Iterator<InnerClassNode> inner = classNode.getInnerClasses(); inner.hasNext(); ) {
        // GROOVY-4004: Clear the methods from the outer class so that they don't get duplicated in
        // inner ones
        propertyMethods.clear();
        propertyMethodsWithSigs.clear();
        constructors.clear();
        printClassContents(out, inner.next());
      }

      out.println("}");
    } finally {
      propertyMethods.clear();
      propertyMethodsWithSigs.clear();
      constructors.clear();
      currentModule = null;
    }
  }