public MethodInfo findRealOverriddenMethod(String name, String signature, HashSet notStrippable) {
    if (mReturnType == null) {
      // ctor
      return null;
    }
    if (mOverriddenMethod != null) {
      return mOverriddenMethod;
    }

    ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
    if (containingClass().realSuperclass() != null
        && containingClass().realSuperclass().isAbstract()) {
      queue.add(containingClass());
    }
    addInterfaces(containingClass().realInterfaces(), queue);
    for (ClassInfo iface : queue) {
      for (MethodInfo me : iface.methods()) {
        if (me.name().equals(name)
            && me.signature().equals(signature)
            && me.inlineTags().tags() != null
            && me.inlineTags().tags().length > 0
            && notStrippable.contains(me.containingClass())) {
          return me;
        }
      }
    }
    return null;
  }
  /**
   * Constructor.
   *
   * @param code The {@link Code} attribute being decompiled.
   */
  public Frame(Code code) {

    operandStack = new Stack<String>();

    localVars = new LocalVarInfo[code.getMaxLocals()];
    int i = 0;
    MethodInfo mi = code.getMethodInfo();

    // Instance methods have an implicit first parameter of "this".
    if (!mi.isStatic()) {
      localVars[i++] = new LocalVarInfo("this", true);
    }

    // Name the passed-in local vars by their types. longs and doubles
    // take up two slots.
    String[] paramTypes = mi.getParameterTypes();
    for (int param_i = 0; param_i < paramTypes.length; param_i++) {
      String type = paramTypes[param_i];
      if (type.indexOf('.') > -1) { // Class types.
        type = type.substring(type.lastIndexOf('.') + 1);
      }
      String name = "localVar_" + type + "_" + param_i;
      localVars[i] = new LocalVarInfo(name, true);
      i++;
      if ("long".equals(type) || "double".equals(type)) {
        i++; // longs and doubles take up two slots.
      }
    }

    // NOTE: Other local vars will still be "null" here!  We need to
    // infer their types from their usage during disassembly/decompilation.
    System.out.println("NOTE: " + (localVars.length - i) + " unknown localVars slots");
  }
  public MethodInfo findSuperclassImplementation(HashSet notStrippable) {
    if (mReturnType == null) {
      // ctor
      return null;
    }
    if (mOverriddenMethod != null) {
      // Even if we're told outright that this was the overridden method, we want to
      // be conservative and ignore mismatches of parameter types -- they arise from
      // extending generic specializations, and we want to consider the derived-class
      // method to be a non-override.
      if (this.signature().equals(mOverriddenMethod.signature())) {
        return mOverriddenMethod;
      }
    }

    ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
    if (containingClass().realSuperclass() != null
        && containingClass().realSuperclass().isAbstract()) {
      queue.add(containingClass());
    }
    addInterfaces(containingClass().realInterfaces(), queue);
    for (ClassInfo iface : queue) {
      for (MethodInfo me : iface.methods()) {
        if (me.name().equals(this.name())
            && me.signature().equals(this.signature())
            && notStrippable.contains(me.containingClass())) {
          return me;
        }
      }
    }
    return null;
  }
 private void addTagToMethod(
     Map<String, MethodInfo> methods, String tagText, MethodTagType tagType) {
   MethodInfo mi = methods.get(methodName);
   if (mi == null) {
     mi = new MethodInfo();
     methods.put(methodName, mi);
   }
   if (tagType == MethodTagType.OMIT_FROM_UI) {
     mi.omitFromUI = true;
     return;
   }
   String[] tagParts =
       Iterables.toArray(
           Splitter.on(WHITESPACE_PATTERN)
               .trimResults()
               .omitEmptyStrings()
               .limit(2)
               .split(tagText),
           String.class);
   if (tagParts.length == 2) {
     if (tagType == MethodTagType.DESCRIPTION) {
       mi.descriptions.put(tagParts[0], tagParts[1]);
     } else {
       mi.useSchemas.put(tagParts[0], tagParts[1]);
     }
   }
 }
 public InheritedTags inherited() {
   MethodInfo m = findOverriddenMethod(name(), signature());
   if (m != null) {
     return m.inlineTags();
   } else {
     return null;
   }
 }
 public MethodParameterInjection copyFrom(@NotNull BaseInjection o) {
   super.copyFrom(o);
   if (o instanceof MethodParameterInjection) {
     final MethodParameterInjection other = (MethodParameterInjection) o;
     myClassName = other.getClassName();
     myParameterMap.clear();
     for (MethodInfo info : other.myParameterMap.values()) {
       myParameterMap.put(info.methodSignature, info.copy());
     }
   }
   return this;
 }
 /**
  * Reads a <code>MethodInfo</code> from an input stream.
  *
  * @param cf The class file defining the method.
  * @param in The input stream to read from.
  * @return The method information read.
  * @throws IOException If an IO error occurs.
  */
 public static MethodInfo read(ClassFile cf, DataInputStream in) throws IOException {
   int accessFlags = in.readUnsignedShort();
   int nameIndex = in.readUnsignedShort();
   int descriptorIndex = in.readUnsignedShort();
   MethodInfo mi = new MethodInfo(cf, accessFlags, nameIndex, descriptorIndex);
   int attrCount = in.readUnsignedShort();
   for (int j = 0; j < attrCount; j++) {
     AttributeInfo ai = mi.readAttribute(in);
     if (ai instanceof Signature) {
       mi.signatureAttr = (Signature) ai;
     } else if (ai instanceof Code) {
       mi.codeAttr = (Code) ai;
     } else if (ai != null) {
       mi.addAttribute(ai);
     }
   }
   return mi;
 }
 public void generate(ClassEmitter ce, Context context, List methods) {
   for (Iterator it = methods.iterator(); it.hasNext(); ) {
     MethodInfo method = (MethodInfo) it.next();
     if (!TypeUtils.isProtected(method.getModifiers())) {
       CodeEmitter e = context.beginMethod(ce, method);
       context.emitCallback(e, context.getIndex(method));
       if (proxyRef) {
         e.load_this();
         e.invoke_interface(PROXY_REF_DISPATCHER, PROXY_REF_LOAD_OBJECT);
       } else {
         e.invoke_interface(DISPATCHER, LOAD_OBJECT);
       }
       e.checkcast(method.getClassInfo().getType());
       e.load_args();
       e.invoke(method);
       e.return_value();
       e.end_method();
     }
   }
 }
  public void generate(ClassEmitter ce, Context context, List methods) {
    for (Iterator it = methods.iterator(); it.hasNext(); ) {
      MethodInfo method = (MethodInfo) it.next();
      Signature impl = context.getImplSignature(method);
      ce.declare_field(Constants.PRIVATE_FINAL_STATIC, impl.getName(), METHOD, null);

      CodeEmitter e = context.beginMethod(ce, method);
      Block handler = e.begin_block();
      context.emitCallback(e, context.getIndex(method));
      e.load_this();
      e.getfield(impl.getName());
      e.create_arg_array();
      e.invoke_interface(INVOCATION_HANDLER, INVOKE);
      e.unbox(method.getSignature().getReturnType());
      e.return_value();
      handler.end();
      EmitUtils.wrap_undeclared_throwable(
          e, handler, method.getExceptionTypes(), UNDECLARED_THROWABLE_EXCEPTION);
      e.end_method();
    }
  }
Exemple #10
0
 private void generateSet(final Class target, final Method[] setters) {
     // setPropertyValues
     CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_PROPERTY_VALUES, null);
     if (setters.length > 0) {
         Local index = e.make_local(Type.INT_TYPE);
         e.push(0);
         e.store_local(index);
         e.load_arg(0);
         e.checkcast(Type.getType(target));
         e.load_arg(1);
         Block handler = e.begin_block();
         int lastIndex = 0;
         for (int i = 0; i < setters.length; i++) {
             if (setters[i] != null) {
                 MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]);
                 int diff = i - lastIndex;
                 if (diff > 0) {
                     e.iinc(index, diff);
                     lastIndex = i;
                 }
                 e.dup2();
                 e.aaload(i);
                 e.unbox(setter.getSignature().getArgumentTypes()[0]);
                 e.invoke(setter);
             }
         }
         handler.end();
         e.return_value();
         e.catch_exception(handler, Constants.TYPE_THROWABLE);
         e.new_instance(BULK_BEAN_EXCEPTION);
         e.dup_x1();
         e.swap();
         e.load_local(index);
         e.invoke_constructor(BULK_BEAN_EXCEPTION, CSTRUCT_EXCEPTION);
         e.athrow();
     } else {
         e.return_value();
     }
     e.end_method();
 }
Exemple #11
0
 private void generateGet(final Class target, final Method[] getters) {
     CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_VALUES, null);
     if (getters.length >= 0) {
         e.load_arg(0);
         e.checkcast(Type.getType(target));
         Local bean = e.make_local();
         e.store_local(bean);
         for (int i = 0; i < getters.length; i++) {
             if (getters[i] != null) {
                 MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]);
                 e.load_arg(1);
                 e.push(i);
                 e.load_local(bean);
                 e.invoke(getter);
                 e.box(getter.getSignature().getReturnType());
                 e.aastore();
             }
         }
     }
     e.return_value();
     e.end_method();
 }
  // first looks for a superclass, and then does a breadth first search to
  // find the least far away match
  public MethodInfo findOverriddenMethod(String name, String signature) {
    if (mReturnType == null) {
      // ctor
      return null;
    }
    if (mOverriddenMethod != null) {
      return mOverriddenMethod;
    }

    ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
    addInterfaces(containingClass().interfaces(), queue);
    for (ClassInfo iface : queue) {
      for (MethodInfo me : iface.methods()) {
        if (me.name().equals(name)
            && me.signature().equals(signature)
            && me.inlineTags().tags() != null
            && me.inlineTags().tags().length > 0) {
          return me;
        }
      }
    }
    return null;
  }
 /**
  * Clone this MethodInfo as if it belonged to the specified ClassInfo and apply the
  * typeArgumentMapping to the parameters and return types.
  */
 public MethodInfo cloneForClass(
     ClassInfo newContainingClass, Map<String, TypeInfo> typeArgumentMapping) {
   TypeInfo returnType = mReturnType.getTypeWithArguments(typeArgumentMapping);
   ArrayList<ParameterInfo> parameters = new ArrayList<ParameterInfo>();
   for (ParameterInfo pi : mParameters) {
     parameters.add(pi.cloneWithTypeArguments(typeArgumentMapping));
   }
   MethodInfo result =
       new MethodInfo(
           getRawCommentText(),
           mTypeParameters,
           name(),
           signature(),
           newContainingClass,
           realContainingClass(),
           isPublic(),
           isProtected(),
           isPackagePrivate(),
           isPrivate(),
           isFinal(),
           isStatic(),
           isSynthetic(),
           mIsAbstract,
           mIsSynchronized,
           mIsNative,
           mIsAnnotationElement,
           kind(),
           mFlatSignature,
           mOverriddenMethod,
           returnType,
           mParameters,
           mThrownExceptions,
           position(),
           annotations());
   result.init(mDefaultAnnotationElementValue);
   return result;
 }
 @NotNull
 public String getDisplayName() {
   final String className = getClassName();
   if (StringUtil.isEmpty(className)) return "<unnamed>";
   MethodInfo singleInfo = null;
   for (MethodInfo info : myParameterMap.values()) {
     if (info.isEnabled()) {
       if (singleInfo == null) {
         singleInfo = info;
       } else {
         singleInfo = null;
         break;
       }
     }
   }
   final String name =
       singleInfo != null
           ? StringUtil.getShortName(className) + "." + singleInfo.methodName
           : StringUtil.getShortName(className);
   return /*"["+getInjectedLanguageId()+"] " +*/ name
       + " ("
       + StringUtil.getPackageName(className)
       + ")";
 }
 @Override
 public void endElement(String uri, String localName, String qName) throws SAXException {
   if (qName.equalsIgnoreCase("class")) {
     classInfo.put(className, oci);
     className = null;
     oci = null;
   } else if (qName.equalsIgnoreCase("comment") && oci != null) {
     if (methodName != null) {
       // do nothing
       if (isGetter(methodName)) {
         MethodInfo mi = oci.getMethods.get(methodName);
         if (mi == null) {
           mi = new MethodInfo();
           oci.getMethods.put(methodName, mi);
         }
         mi.comment = comment.toString();
       } else if (isSetter(methodName)) {
         MethodInfo mi = oci.setMethods.get(methodName);
         if (mi == null) {
           mi = new MethodInfo();
           oci.setMethods.put(methodName, mi);
         }
         mi.comment = comment.toString();
       }
     } else if (fieldName != null) {
       oci.fields.put(fieldName, comment.toString());
     } else {
       oci.comment = comment.toString();
     }
     comment = null;
   } else if (qName.equalsIgnoreCase("field")) {
     fieldName = null;
   } else if (qName.equalsIgnoreCase("method")) {
     methodName = null;
   }
 }
  /**
   * Finds the original method name(s), appending the first one to the out line, and any additional
   * alternatives to the extra lines.
   */
  private void originalMethodName(
      String className,
      String obfuscatedMethodName,
      int lineNumber,
      String type,
      String arguments,
      StringBuffer outLine,
      List extraOutLines) {
    int extraIndent = -1;

    // Class name -> obfuscated method names.
    Map methodMap = (Map) classMethodMap.get(className);
    if (methodMap != null) {
      // Obfuscated method names -> methods.
      Set methodSet = (Set) methodMap.get(obfuscatedMethodName);
      if (methodSet != null) {
        // Find all matching methods.
        Iterator methodInfoIterator = methodSet.iterator();
        while (methodInfoIterator.hasNext()) {
          MethodInfo methodInfo = (MethodInfo) methodInfoIterator.next();
          if (methodInfo.matches(lineNumber, type, arguments)) {
            // Is this the first matching method?
            if (extraIndent < 0) {
              extraIndent = outLine.length();

              // Append the first original name.
              if (verbose) {
                outLine.append(methodInfo.type).append(' ');
              }
              outLine.append(methodInfo.originalName);
              if (verbose) {
                outLine.append('(').append(methodInfo.arguments).append(')');
              }
            } else {
              // Create an additional line with the proper
              // indentation.
              StringBuffer extraBuffer = new StringBuffer();
              for (int counter = 0; counter < extraIndent; counter++) {
                extraBuffer.append(' ');
              }

              // Append the alternative name.
              if (verbose) {
                extraBuffer.append(methodInfo.type).append(' ');
              }
              extraBuffer.append(methodInfo.originalName);
              if (verbose) {
                extraBuffer.append('(').append(methodInfo.arguments).append(')');
              }

              // Store the additional line.
              extraOutLines.add(extraBuffer);
            }
          }
        }
      }
    }

    // Just append the obfuscated name if we haven't found any matching
    // methods.
    if (extraIndent < 0) {
      outLine.append(obfuscatedMethodName);
    }
  }
  protected void writeAllNativeTables(ClassClass classes[]) {
    sortClasses(classes);
    Vector nativeClasses = new Vector();

    // (1) Write all the function declarations
    for (int i = 0; i < classes.length; i++) {
      boolean classHasNatives = false;
      EVMClass cc = (EVMClass) classes[i];
      if (cc.isPrimitiveClass() || cc.isArrayClass()) {
        continue;
      }
      EVMMethodInfo m[] = cc.methods;
      sortMethods(m);
      int nmethod = (m == null) ? 0 : m.length;
      for (int j = 0; j < nmethod; j++) {
        EVMMethodInfo meth = m[j];
        MethodInfo mi = meth.method;
        if (!isNativeOrEntryFunc(cc, mi)) {
          continue;
        }
        if (!classHasNatives) {
          classHasNatives = true;
          nativeClasses.addElement(cc);
        }
        int entry;
        entry = checkEntry(cc, mi);
        if (entry < 0 || use_entries[entry].length > 4) {
          // This is a "native"
          out.println(
              "extern \"C\" " + mi.getJNIReturnType() + " " + mi.getNativeName(true) + "();");
        }
        if (entry >= 0) {
          // This is an "entry" (could also be a "native")
          out.println("extern \"C\" void " + use_entries[entry][3] + "();");
        }
      }
    }
    out.println();
    out.println();

    // (2) Write all the "_natives[]" and "_entries[]" tables for
    //     individual classes

    for (Enumeration e = nativeClasses.elements(); e.hasMoreElements(); ) {
      EVMClass cc = (EVMClass) e.nextElement();
      EVMMethodInfo m[] = cc.methods;
      int nmethod = (m == null) ? 0 : m.length;
      int num_native_methods = 0;
      int num_entry_methods = 0;

      for (int j = 0; j < nmethod; j++) {
        EVMMethodInfo meth = m[j];
        MethodInfo mi = meth.method;
        if (!isNativeOrEntryFunc(cc, mi)) {
          continue;
        }
        if (isNativeFunc(cc, mi)) {
          num_native_methods++;
        }
        if (isEntryFunc(cc, mi)) {
          num_entry_methods++;
        }
      }

      // Write the "_natives[]" struct
      if (num_native_methods > 0) {
        out.println("static const JvmNativeFunction " + cc.getNativeName() + "_natives[] = " + "{");
        for (int j = 0; j < nmethod; j++) {
          EVMMethodInfo meth = m[j];
          MethodInfo mi = meth.method;
          if (!isNativeOrEntryFunc(cc, mi)) {
            continue;
          }
          if (isNativeFunc(cc, mi)) {
            out.print(pad("  JVM_NATIVE(\"" + mi.name.string + "\",", 30));
            out.print(pad("\"" + mi.type.string + "\", ", 25));
            out.println(mi.getNativeName(true) + "),");
          }
        }
        out.println("  {(char*)0, (char*)0, (void*)0}");
        out.println("};");
        out.println();
      }

      // Write the "_entries[]" struct
      if (num_entry_methods > 0) {
        out.println("static const JvmNativeFunction " + cc.getNativeName() + "_entries[] = " + "{");
        for (int j = 0; j < nmethod; j++) {
          EVMMethodInfo meth = m[j];
          MethodInfo mi = meth.method;
          if (!isNativeOrEntryFunc(cc, mi)) {
            continue;
          }
          int entry;
          if ((entry = checkEntry(cc, mi)) >= 0) {
            out.print(
                "  JVM_ENTRY(\"" + mi.name.string + "\"," + spaces(20 - mi.name.string.length()));
            out.print("\"" + mi.type.string + "\", ");
            out.println(use_entries[entry][3] + "),");
          }
        }
        out.println("  {(char*)0, (char*)0, (void*)0}");
        out.println("};");
        out.println();
      }
    }

    // (3) Write the top-level table

    out.println("const JvmNativesTable jvm_natives_table[] = {");

    for (Enumeration e = nativeClasses.elements(); e.hasMoreElements(); ) {
      EVMClass cc = (EVMClass) e.nextElement();
      String className = cc.ci.className;
      out.println("  JVM_TABLE(\"" + className + "\",");
      EVMMethodInfo m[] = cc.methods;
      int nmethod = (m == null) ? 0 : m.length;

      int num_native_methods = 0;
      int num_entry_methods = 0;

      for (int j = 0; j < nmethod; j++) {
        EVMMethodInfo meth = m[j];
        MethodInfo mi = meth.method;
        if (!isNativeOrEntryFunc(cc, mi)) {
          continue;
        }
        if (isNativeFunc(cc, mi)) {
          num_native_methods++;
        }
        if (isEntryFunc(cc, mi)) {
          num_entry_methods++;
        }
      }

      if (num_native_methods > 0) {
        out.println(spaces(40) + cc.getNativeName() + "_natives,");
      } else {
        out.println(spaces(40) + "(JvmNativeFunction*)0,");
      }
      if (num_entry_methods > 0) {
        out.println(spaces(40) + cc.getNativeName() + "_entries),");
      } else {
        out.println(spaces(40) + "(JvmNativeFunction*)0),");
      }
    }
    out.println("  JVM_TABLE((char*)0, (JvmNativeFunction*)0, " + "(JvmNativeFunction*)0)");
    out.println("};");

    // (4) Write the jvm_native_execution_top-level table

    out.println("const JvmExecutionEntry jvm_api_entries[] = {");
    for (Enumeration e = nativeClasses.elements(); e.hasMoreElements(); ) {
      EVMClass cc = (EVMClass) e.nextElement();
      EVMMethodInfo m[] = cc.methods;
      int nmethod = (m == null) ? 0 : m.length;

      for (int j = 0; j < nmethod; j++) {
        EVMMethodInfo meth = m[j];
        MethodInfo mi = meth.method;
        int index;
        if ((index = checkEntry(cc, mi)) >= 0) {
          String entryName = use_entries[index][3];
          out.println("{(unsigned char*)&" + entryName + ",");
          out.println("(char*)\"" + entryName + "\"},");
        }
      }
    }
    out.println("{(unsigned char*)0, (char*)0}};");
  }
 public void setMethodInfos(final Collection<MethodInfo> newInfos) {
   myParameterMap.clear();
   for (MethodInfo methodInfo : newInfos) {
     myParameterMap.put(methodInfo.getMethodSignature(), methodInfo);
   }
 }
Exemple #19
0
  public ObjectDescription generateObjectDescription(Object o, Integer objID, boolean addObject) {

    ObjectDescription result = null;

    // Object annotations
    ObjectInfo objectInfo = null;

    Annotation[] objectAnnotations = o.getClass().getAnnotations();

    for (Annotation a : objectAnnotations) {
      if (a.annotationType().equals(ObjectInfo.class)) {
        objectInfo = (ObjectInfo) a;
        break;
      }
    }

    if (addObject) {
      ObjectEntry oEntry = new ObjectEntry(o);
      if (objID != null) {
        objects.addWithID(oEntry, objID);
      } else {
        objects.add(oEntry);
        objID = oEntry.getID();
      }
    }

    boolean hasCustomReferenceMethod = false;

    // we need special treatment for proxy objects
    if (o instanceof ProxyObject) {
      ProxyObject proxy = (ProxyObject) o;

      result = proxy.getObjectDescription();

      result.setName(o.getClass().getName());

      result.setID(objID);

      // update objID of methods
      for (MethodDescription mDesc : result.getMethods()) {
        mDesc.setObjectID(objID);
      }

    } else {
      result = new ObjectDescription();
      result.setInfo(objectInfo);

      result.setName(o.getClass().getName());

      result.setID(objID);

      Class<?> c = o.getClass();

      Method[] theMethods = null;

      if (objectInfo != null && objectInfo.showInheritedMethods()) {
        theMethods = c.getMethods();
      } else {
        ArrayList<Method> methods = new ArrayList<Method>();

        // methods declared by class c
        for (Method m : c.getDeclaredMethods()) {
          methods.add(m);
        }

        // methods declared in superclasses of c
        for (Method m : c.getMethods()) {
          MethodInfo info = m.getAnnotation(MethodInfo.class);
          // if m is marked as inheritGUI this method will
          // be visualized even if it is a method declared
          // in a superclass of c
          if (info != null && info.inheritGUI()) {
            if (!methods.contains(m)) {
              methods.add(m);
            }
          }
        }

        Method[] tmpArray = new Method[methods.size()];

        theMethods = methods.toArray(tmpArray);
      }

      for (int i = 0; i < theMethods.length; i++) {

        // filter groovy object specific methods
        String method = theMethods[i].getName();
        boolean isGroovyObject = o instanceof GroovyObject;
        boolean isGroovyMethod =
            method.equals("setProperty")
                || method.equals("getProperty")
                || method.equals("invokeMethod")
                || method.equals("getMetaClass")
                || method.equals("setMetaClass"); // ||
        //                            // the following methods are only present
        //                            // for Groovy >= 1.6
        //                            method.equals("super$1$wait") ||
        //                            method.equals("super$1$toString") ||
        //                            method.equals("super$1$notify") ||
        //                            method.equals("super$1$notifyAll") ||
        //                            method.equals("super$1$getClass") ||
        //                            method.equals("super$1$equals") ||
        //                            method.equals("super$1$clone") ||
        //                            method.equals("super$1$hashCode") ||
        //                            method.equals("super$1$finalize");

        // For Groovy >= 1.6 private methods have $ sign in their
        // name, e.g.,
        //   private doSomething()
        // will be changed to
        //   this$2$doSomething()
        // which is unfortunately accessible and thus will be
        // visualized by vrl.
        // To prevent groovys strange behavior
        // methods with $ sign are ignored and treated as private.
        boolean isPrivateGroovyMethod = method.contains("$");

        // TODO improve that code!
        if ((isGroovyObject && isGroovyMethod) || isPrivateGroovyMethod) {
          continue;
        }

        Class[] parameterTypes = theMethods[i].getParameterTypes();

        Annotation[][] allParameterAnnotations = theMethods[i].getParameterAnnotations();

        ArrayList<String> paramNames = new ArrayList<String>();

        ArrayList<ParamInfo> paramAnnotations = new ArrayList<ParamInfo>();
        ArrayList<ParamGroupInfo> paramGroupAnnotations = new ArrayList<ParamGroupInfo>();

        // retrieving annotation information for each parameter
        for (int j = 0; j < allParameterAnnotations.length; j++) {

          Annotation[] annotations = allParameterAnnotations[j];

          // add name element and set it to null
          // because we don't know if parameter j is annotated
          paramNames.add(null);
          paramAnnotations.add(null);
          paramGroupAnnotations.add(null);

          // check all annotations of parameter j
          // if we have a ParamInfo annotation retrieve data
          // and store it as element of paramName
          for (Annotation a : annotations) {
            if (a.annotationType().equals(ParamInfo.class)) {
              ParamInfo n = (ParamInfo) a;
              if (!n.name().equals("")) {
                paramNames.set(j, n.name());
              }
              paramAnnotations.set(j, n);
            } else {
              if (a.annotationType().equals(ParamGroupInfo.class)) {
                ParamGroupInfo n = (ParamGroupInfo) a;
                paramGroupAnnotations.set(j, n);
              }
            }
          } // end for a
        } // end for j

        // convert list to array
        String[] parameterNames = paramNames.toArray(new String[paramNames.size()]);

        ParamInfo[] parameterAnnotations =
            paramAnnotations.toArray(new ParamInfo[paramAnnotations.size()]);

        ParamGroupInfo[] parameterGroupAnnotations =
            paramGroupAnnotations.toArray(new ParamGroupInfo[paramGroupAnnotations.size()]);

        Class returnType = theMethods[i].getReturnType();

        String methodString = theMethods[i].getName();
        String methodTitle = "";
        String returnValueName = null;

        int modifiers = theMethods[i].getModifiers();

        String modifierString = Modifier.toString(modifiers);

        // Method Annotations
        Annotation[] annotations = theMethods[i].getAnnotations();
        MethodInfo methodInfo = null;

        OutputInfo outputInfo = null;

        boolean interactive = true;
        boolean hide = false;

        for (Annotation a : annotations) {
          if (a.annotationType().equals(MethodInfo.class)) {
            MethodInfo n = (MethodInfo) a;

            methodTitle = n.name();
            interactive = n.interactive();
            hide = n.hide();
            returnValueName = n.valueName();

            methodInfo = n;
          }

          if (a.annotationType().equals(OutputInfo.class)) {
            outputInfo = (OutputInfo) a;
          }
        }

        if (theMethods[i].getAnnotation(ReferenceMethodInfo.class) != null) {
          hasCustomReferenceMethod = true;
          MethodDescription customReferenceMethod =
              new MethodDescription(
                  objID,
                  0,
                  methodString,
                  methodTitle,
                  null,
                  parameterTypes,
                  parameterNames,
                  parameterAnnotations,
                  parameterGroupAnnotations,
                  returnType,
                  returnValueName,
                  interactive,
                  methodInfo,
                  outputInfo);

          if (customReferenceMethod.getParameterTypes() == null
              || customReferenceMethod.getParameterTypes().length != 1) {
            throw new IllegalArgumentException(
                " Cannot to use "
                    + "\""
                    + methodString
                    + "\" as reference method"
                    + " because the number of parameters does not"
                    + " match. Exactly one parameter must be"
                    + " provided.");
          }

          if (customReferenceMethod.getReturnType() == void.class
              || customReferenceMethod.getReturnType().isPrimitive()) {
            throw new IllegalArgumentException(
                " Cannot to use "
                    + "\""
                    + methodString
                    + "\" as reference method"
                    + " because it does not return an object."
                    + " Returning primitives or void is not"
                    + " allowed.");
          }

          customReferenceMethod.setMethodType(MethodType.CUSTOM_REFERENCE);

          result.addMethod(customReferenceMethod);
        } //
        // TODO: at the moment method id is always 0 and will only be
        //      set from corresponding method representations
        //
        //      is it necessary to change that?
        else if (modifierString.contains("public")
            && (methodInfo == null || !methodInfo.ignore())) {
          result.addMethod(
              new MethodDescription(
                  objID,
                  0,
                  methodString,
                  methodTitle,
                  null,
                  parameterTypes,
                  parameterNames,
                  parameterAnnotations,
                  parameterGroupAnnotations,
                  returnType,
                  returnValueName,
                  interactive,
                  methodInfo,
                  outputInfo));
        }
      } // end for i

      // Object name
      if (objectInfo != null && !objectInfo.name().equals("")) {
        result.setName(objectInfo.name());
      }
    } // end else if (o instanceof ProxyObject)

    if (!hasCustomReferenceMethod) {
      result.addMethod(MethodDescription.createReferenceMethod(objID, o.getClass()));
    }

    return result;
  }
 public int compare(MethodInfo a, MethodInfo b) {
   return a.name().compareTo(b.name());
 }
  public boolean isConsistent(MethodInfo mInfo) {
    boolean consistent = true;
    if (this.mReturnType != mInfo.mReturnType && !this.mReturnType.equals(mInfo.mReturnType)) {
      if (!mReturnType.isPrimitive() && !mInfo.mReturnType.isPrimitive()) {
        // Check to see if our class extends the old class.
        ApiInfo infoApi = mInfo.containingClass().containingPackage().containingApi();
        ClassInfo infoReturnClass = infoApi.findClass(mInfo.mReturnType.qualifiedTypeName());
        // Find the classes.
        consistent =
            infoReturnClass != null
                && infoReturnClass.isAssignableTo(mReturnType.qualifiedTypeName());
      } else {
        consistent = false;
      }

      if (!consistent) {
        Errors.error(
            Errors.CHANGED_TYPE,
            mInfo.position(),
            "Method "
                + mInfo.qualifiedName()
                + " has changed return type from "
                + mReturnType
                + " to "
                + mInfo.mReturnType);
      }
    }

    if (mIsAbstract != mInfo.mIsAbstract) {
      consistent = false;
      Errors.error(
          Errors.CHANGED_ABSTRACT,
          mInfo.position(),
          "Method " + mInfo.qualifiedName() + " has changed 'abstract' qualifier");
    }

    if (mIsNative != mInfo.mIsNative) {
      consistent = false;
      Errors.error(
          Errors.CHANGED_NATIVE,
          mInfo.position(),
          "Method " + mInfo.qualifiedName() + " has changed 'native' qualifier");
    }

    if (!mIsStatic) {
      // Compiler-generated methods vary in their 'final' qualifier between versions of
      // the compiler, so this check needs to be quite narrow. A change in 'final'
      // status of a method is only relevant if (a) the method is not declared 'static'
      // and (b) the method is not already inferred to be 'final' by virtue of its class.
      if (!isEffectivelyFinal() && mInfo.isEffectivelyFinal()) {
        consistent = false;
        Errors.error(
            Errors.ADDED_FINAL,
            mInfo.position(),
            "Method " + mInfo.qualifiedName() + " has added 'final' qualifier");
      } else if (isEffectivelyFinal() && !mInfo.isEffectivelyFinal()) {
        consistent = false;
        Errors.error(
            Errors.REMOVED_FINAL,
            mInfo.position(),
            "Method " + mInfo.qualifiedName() + " has removed 'final' qualifier");
      }
    }

    if (mIsStatic != mInfo.mIsStatic) {
      consistent = false;
      Errors.error(
          Errors.CHANGED_STATIC,
          mInfo.position(),
          "Method " + mInfo.qualifiedName() + " has changed 'static' qualifier");
    }

    if (!scope().equals(mInfo.scope())) {
      consistent = false;
      Errors.error(
          Errors.CHANGED_SCOPE,
          mInfo.position(),
          "Method "
              + mInfo.qualifiedName()
              + " changed scope from "
              + scope()
              + " to "
              + mInfo.scope());
    }

    if (!isDeprecated() == mInfo.isDeprecated()) {
      Errors.error(
          Errors.CHANGED_DEPRECATED,
          mInfo.position(),
          "Method "
              + mInfo.qualifiedName()
              + " has changed deprecation state "
              + isDeprecated()
              + " --> "
              + mInfo.isDeprecated());
      consistent = false;
    }

    // see JLS 3 13.4.20 "Adding or deleting a synchronized modifier of a method does not break "
    // "compatibility with existing binaries."
    /*
    if (mIsSynchronized != mInfo.mIsSynchronized) {
      Errors.error(Errors.CHANGED_SYNCHRONIZED, mInfo.position(), "Method " + mInfo.qualifiedName()
          + " has changed 'synchronized' qualifier from " + mIsSynchronized + " to "
          + mInfo.mIsSynchronized);
      consistent = false;
    }
    */

    for (ClassInfo exception : thrownExceptions()) {
      if (!mInfo.throwsException(exception)) {
        // exclude 'throws' changes to finalize() overrides with no arguments
        if (!name().equals("finalize") || (!mParameters.isEmpty())) {
          Errors.error(
              Errors.CHANGED_THROWS,
              mInfo.position(),
              "Method "
                  + mInfo.qualifiedName()
                  + " no longer throws exception "
                  + exception.qualifiedName());
          consistent = false;
        }
      }
    }

    for (ClassInfo exec : mInfo.thrownExceptions()) {
      // exclude 'throws' changes to finalize() overrides with no arguments
      if (!throwsException(exec)) {
        if (!name().equals("finalize") || (!mParameters.isEmpty())) {
          Errors.error(
              Errors.CHANGED_THROWS,
              mInfo.position(),
              "Method "
                  + mInfo.qualifiedName()
                  + " added thrown exception "
                  + exec.qualifiedName());
          consistent = false;
        }
      }
    }

    return consistent;
  }
 public boolean matches(MethodInfo other) {
   return prettySignature().equals(other.prettySignature());
 }
  public ParamTagInfo[] paramTags() {
    if (mParamTags == null) {
      final int N = mParameters.size();

      String[] names = new String[N];
      String[] comments = new String[N];
      SourcePositionInfo[] positions = new SourcePositionInfo[N];

      // get the right names so we can handle our names being different from
      // our parent's names.
      int i = 0;
      for (ParameterInfo param : mParameters) {
        names[i] = param.name();
        comments[i] = "";
        positions[i] = param.position();
        i++;
      }

      // gather our comments, and complain about misnamed @param tags
      for (ParamTagInfo tag : comment().paramTags()) {
        int index = indexOfParam(tag.parameterName(), names);
        if (index >= 0) {
          comments[index] = tag.parameterComment();
          positions[index] = tag.position();
        } else {
          Errors.error(
              Errors.UNKNOWN_PARAM_TAG_NAME,
              tag.position(),
              "@param tag with name that doesn't match the parameter list: '"
                  + tag.parameterName()
                  + "'");
        }
      }

      // get our parent's tags to fill in the blanks
      MethodInfo overridden = this.findOverriddenMethod(name(), signature());
      if (overridden != null) {
        ParamTagInfo[] maternal = overridden.paramTags();
        for (i = 0; i < N; i++) {
          if (comments[i].equals("")) {
            comments[i] = maternal[i].parameterComment();
            positions[i] = maternal[i].position();
          }
        }
      }

      // construct the results, and cache them for next time
      mParamTags = new ParamTagInfo[N];
      for (i = 0; i < N; i++) {
        mParamTags[i] =
            new ParamTagInfo(
                "@param", "@param", names[i] + " " + comments[i], parent(), positions[i]);

        // while we're here, if we find any parameters that are still undocumented at this
        // point, complain. (this warning is off by default, because it's really, really
        // common; but, it's good to be able to enforce it)
        if (comments[i].equals("")) {
          Errors.error(
              Errors.UNDOCUMENTED_PARAMETER,
              positions[i],
              "Undocumented parameter '" + names[i] + "' on method '" + name() + "'");
        }
      }
    }
    return mParamTags;
  }