/**
   * Returns the signature of this method, as determined from its method descriptor.
   *
   * @return The signature of this method.
   */
  public String getSignature() {

    StringBuffer sb = new StringBuffer();

    // Return type.
    if (!isConstructor()) { // Don't print "void" return type.
      sb.append(getReturnTypeString(false));
      sb.append(' ');
    }

    // Method name and param list.
    sb.append(getName());
    sb.append('(');
    appendParamDescriptors(sb);
    sb.append(')');

    // "throws" clause.
    for (int i = 0; i < getAttributeCount(); i++) {
      AttributeInfo ai = (AttributeInfo) attributes.get(i);
      if (ai instanceof Exceptions) { // At most 1 Exceptions attribute
        sb.append(" throws ");
        Exceptions ex = (Exceptions) ai;
        for (int j = 0; j < ex.getExceptionCount(); j++) {
          sb.append(ex.getException(j));
          if (j < ex.getExceptionCount() - 1) {
            sb.append(", ");
          }
        }
      }
    }

    return sb.toString();
  }
  private void appendParamDescriptors(StringBuffer sb) {

    String[] paramTypes = getParameterTypes();
    for (int i = 0; i < paramTypes.length; i++) {
      sb.append(paramTypes[i]).append(" param").append(i);
      if (i < paramTypes.length - 1) {
        sb.append(", ");
      }
    }
  }
  /**
   * Returns the name and parameters of this method, in the form <code>
   * performAction(String, int, Runnable)</code>.
   *
   * @return The name and parameters of this method.
   */
  public String getNameAndParameters() {

    if (nameAndParameters == null) {

      StringBuffer sb = new StringBuffer(getName());

      sb.append('(');
      int paramCount = getParameterCount();
      for (int i = 0; i < paramCount; i++) {
        sb.append(getParameterType(i, false));
        if (i < paramCount - 1) {
          sb.append(", ");
        }
      }
      sb.append(')');

      nameAndParameters = sb.toString();
    }

    return nameAndParameters;
  }
  /*
   * TODO: This is identical to FieldInfo.getTypeString(), except for the
   * 'V' case.  It is also very similar to #getParameterTypes().  Try
   * to refactor common code from these methods.
   */
  private String getReturnTypeStringFromDescriptor(boolean qualified) {

    String descriptor = getDescriptor();
    int rparen = descriptor.indexOf(')');
    descriptor = descriptor.substring(rparen + 1); // return type desc.
    StringBuffer sb = new StringBuffer();

    int braceCount = descriptor.lastIndexOf('[') + 1;

    switch (descriptor.charAt(braceCount)) {

        // BaseType
      case 'B':
        sb.append("byte");
        break;
      case 'C':
        sb.append("char");
        break;
      case 'D':
        sb.append("double");
        break;
      case 'F':
        sb.append("float");
        break;
      case 'I':
        sb.append("int");
        break;
      case 'J':
        sb.append("long");
        break;
      case 'S':
        sb.append("short");
        break;
      case 'Z':
        sb.append("boolean");
        break;
      case 'V':
        sb.append("void");
        break;

        // ObjectType
      case 'L':
        String clazz = descriptor.substring(1, descriptor.length() - 1);
        // clazz = clazz.substring(clazz.lastIndexOf('/')+1);
        clazz =
            qualified
                ? org.fife.rsta.ac.java.Util.replaceChar(clazz, '/', '.')
                : clazz.substring(clazz.lastIndexOf('/') + 1);
        // clazz = clazz.substring(clazz.lastIndexOf('/')+1);
        sb.append(clazz);
        break;

        // Invalid field descriptor
      default:
        sb.append("UNSUPPORTED_TYPE_").append(descriptor);
        break;
    }

    for (int i = 0; i < braceCount; i++) {
      sb.append("[]");
    }

    return sb.toString();
  }