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(); } }
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(); }
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); } }
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; }