/** Extract the Type information from a TYPE node. */
  private static String _typeName(IterableTree ast) {
    if (ast == null) {
      return null;
    }
    StringBuilder typeName = new StringBuilder();

    if (ast.getType() == JavaParser.TYPE) {

      IterableTree qualifiedType = ast.firstChildOfType(JavaParser.QUALIFIED_TYPE_IDENT);

      if (qualifiedType != null) {
        StringBuilder qualifiedTypeName = new StringBuilder();
        for (int i = 0; i < qualifiedType.getChildCount(); i++) {
          qualifiedTypeName.append("." + qualifiedType.getChild(i).getText());

          IterableTree generics =
              qualifiedType.getChild(i).firstChildOfType(JavaParser.GENERIC_TYPE_ARG_LIST);
          if (generics != null) {
            qualifiedTypeName.append('<');
            qualifiedTypeName.append(_genericsTypeList(generics));
            qualifiedTypeName.append('>');
          }
        }
        /* to remove the leading dot */
        typeName.append(qualifiedTypeName.substring(1));
      } else {
        typeName.append(ast.getChild(0).getText());
      }

      Tree arrayDecl = ast.firstChildOfType(JavaParser.ARRAY_DECLARATOR_LIST);
      if (arrayDecl != null) {
        for (int i = 0; i < arrayDecl.getChildCount(); i++) {
          typeName.append("[]");
        }
      }

    } else if (ast.getType() == JavaParser.QUESTION) {
      typeName.append("?");

      if (ast.getChildCount() > 0) {
        /* ^(QUESTION ^(EXTENDS|SUPER type)) */
        IterableTree extendsAst = ast.getChild(0);
        typeName.append(" ");
        typeName.append(extendsAst.getText());
        typeName.append(" ");
        typeName.append(_typeName(extendsAst.getChild(0)));
      }
    }

    return typeName.toString();
  }
  /**
   * Extract the generic type list from a type.
   *
   * <p>Such as Blah<GenericType1, GenericType2>
   */
  private static String _genericsTypeList(IterableTree ast) {

    StringBuilder generics = new StringBuilder();

    for (IterableTree child : ast) {
      generics.append(", ");
      switch (child.getType()) {
        case JavaParser.TYPE:
          generics.append(_typeName(child));
          break;
        case JavaParser.IDENT:
          generics.append(child.getText());
          IterableTree bounds = child.firstChildOfType(JavaParser.EXTENDS_BOUND_LIST);
          if (bounds != null) {
            generics.append(" extends ");
            for (IterableTree bound : bounds) {
              generics.append(_typeName(bound));
              generics.append(" & ");
            }
            /* we remove the trailing " & " */
            generics.delete(generics.length() - " & ".length(), generics.length());
          }
          break;
        default:
          break;
      }
    }

    return generics.substring(2); /* remove the leading ", " */
  }
 /** Handle import nodes ^(IMPORT ...) */
 private void __import(IterableTree ast) {
   for (IterableTree node : ast) {
     if (node.getType() != JavaParser.STATIC) {
       String importName = _dottedName(node);
       ((APIScope) scopeStack.peek()).dependencies.add(importName);
       return;
     }
   }
 }
 private static String _dottedName(IterableTree ast) {
   StringBuilder buffer = new StringBuilder();
   switch (ast.getType()) {
     case JavaParser.IDENT:
       buffer.append(ast.getText());
       break;
     case JavaParser.DOT:
       buffer.append(_dottedName(ast.getChild(0)));
       buffer.append(".");
       buffer.append(_dottedName(ast.getChild(1)));
       break;
     default:
       break;
   }
   return buffer.toString();
 }
 /** Extract the "visibility" information from a MODIFIER_LIST node. */
 private static Visibility _javaVisibility(IterableTree ast) {
   if (ast != null) {
     for (IterableTree child : ast) {
       switch (child.getType()) {
         case JavaParser.PUBLIC:
           return Visibility.PUBLIC;
         case JavaParser.PRIVATE:
           return Visibility.PRIVATE;
         case JavaParser.PROTECTED:
           return Visibility.PROTECTED;
         default:
           continue;
       }
     }
   }
   return Visibility.SCOPE;
 }
 /** Extract the modifiers from a MODIFIER_LIST node (without the "visibility" information) */
 private static Set<String> _javaModifiers(IterableTree ast) {
   Set<String> modifiers = new HashSet<String>();
   if (ast != null) {
     for (IterableTree child : ast) {
       switch (child.getType()) {
         case JavaParser.PUBLIC:
         case JavaParser.PRIVATE:
         case JavaParser.PROTECTED:
           break;
         case JavaParser.AT:
           modifiers.add("@" + _dottedName(child.getChild(0)));
           break;
         default:
           modifiers.add(child.getText());
       }
     }
   }
   return modifiers;
 }
  /** Walk a Java Tree and fill "globalScope" with generic API information from it. */
  @Override
  public void walk(IterableTree ast) {

    if (ast == null) {
      return;
    }

    switch (ast.getType()) {
      case JavaParser.JAVA_SOURCE:
        __root(ast);
        break;

      case JavaParser.IMPORT:
        __import(ast);
        break;

      case JavaParser.ENUM:
      case JavaParser.CLASS:
      case JavaParser.INTERFACE:
        __object(ast);
        break;

      case JavaParser.EXTENDS_CLAUSE:
      case JavaParser.IMPLEMENTS_CLAUSE:
        __extends(ast);
        break;

      case JavaParser.CLASS_TOP_LEVEL_SCOPE:
      case JavaParser.INTERFACE_TOP_LEVEL_SCOPE:
      case JavaParser.ENUM_TOP_LEVEL_SCOPE:
        walkChildren(ast);
        break;

      case JavaParser.VAR_DECLARATION:
        __variable(ast);
        break;

      case JavaParser.CONSTRUCTOR_DECL:
      case JavaParser.FUNCTION_METHOD_DECL:
      case JavaParser.VOID_METHOD_DECL:
        __function(ast);
        break;

      case JavaParser.FORMAL_PARAM_LIST:
        walkChildren(ast);
        break;

      case JavaParser.FORMAL_PARAM_VARARG_DECL:
        ((Function) scopeStack.peek()).hasVarArgs = true;
        /* fallback to next case option */
      case JavaParser.FORMAL_PARAM_STD_DECL:
        __argument(ast);
        break;

      case JavaParser.THROWS_CLAUSE:
        __exceptions(ast);
        break;

      default:
        break;
    }
  }