// changed API of IBinaryMethod (between Eclipse 4.5 and Eclipse 4.6) // therefore adapting to this via reflection to use the correct existing method private static IBinaryAnnotation[] getParameterAnnotation( IBinaryMethod newMethod, int i, char[] fileName) { IBinaryAnnotation[] result = null; // try the old method first try { try { Method getParameterAnnotationsMethod = newMethod.getClass().getMethod("getParameterAnnotations", int.class); if (getParameterAnnotationsMethod != null) { getParameterAnnotationsMethod.setAccessible(true); result = (IBinaryAnnotation[]) getParameterAnnotationsMethod.invoke(newMethod, i); } } catch (NoSuchMethodException e) { // if the old method is not there, try the new one Method getParameterAnnotationsMethod = newMethod.getClass().getMethod("getParameterAnnotations", int.class, char[].class); if (getParameterAnnotationsMethod != null) { getParameterAnnotationsMethod.setAccessible(true); result = (IBinaryAnnotation[]) getParameterAnnotationsMethod.invoke(newMethod, i, fileName); } } } catch (Exception e) { SpringCore.log(e); } return result; }
private static boolean parameterAnnotationsEquals( IBinaryMethod newMethod, IBinaryMethod existingMethod, char[] fileName, int flags) { char[][] argumentNames = newMethod.getArgumentNames(); char[][] existingArgumentNames = existingMethod.getArgumentNames(); if (argumentNames == null && existingArgumentNames == null) return true; int argumentCount = argumentNames != null ? argumentNames.length : 0; int existingArgumentCount = existingArgumentNames != null ? existingArgumentNames.length : 0; if (argumentCount != existingArgumentCount) return false; for (int i = 0; i < argumentCount; i++) { IBinaryAnnotation[] parameterAnnotations = getParameterAnnotation(newMethod, i, fileName); IBinaryAnnotation[] existingParameterAnnotations = getParameterAnnotation(existingMethod, i, fileName); if (!annotationsEqual(parameterAnnotations, existingParameterAnnotations, flags)) { return false; } } return true; }
boolean matchMethod(MethodPattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) { if (!pattern.findDeclarations) return false; // only relevant when finding declarations if (!(binaryInfo instanceof IBinaryMethod)) return false; IBinaryMethod method = (IBinaryMethod) binaryInfo; if (!pattern.matchesName(pattern.selector, method.getSelector())) return false; if (!checkDeclaringType( enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; // look at return type only if declaring type is not specified boolean checkReturnType = pattern.declaringSimpleName == null && (pattern.returnSimpleName != null || pattern.returnQualification != null); boolean checkParameters = pattern.parameterSimpleNames != null; if (checkReturnType || checkParameters) { char[] methodDescriptor = convertClassFileFormat(method.getMethodDescriptor()); if (checkReturnType) { char[] returnTypeSignature = Signature.toCharArray(Signature.getReturnType(methodDescriptor)); if (!checkTypeName( pattern.returnSimpleName, pattern.returnQualification, returnTypeSignature, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; } if (checkParameters && !checkParameters( methodDescriptor, pattern.parameterSimpleNames, pattern.parameterQualifications, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; } return true; }
boolean matchConstructor( ConstructorPattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) { if (!pattern.findDeclarations) return false; // only relevant when finding declarations if (!(binaryInfo instanceof IBinaryMethod)) return false; IBinaryMethod method = (IBinaryMethod) binaryInfo; if (!method.isConstructor()) return false; if (!checkDeclaringType( enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; if (pattern.parameterSimpleNames != null) { char[] methodDescriptor = convertClassFileFormat(method.getMethodDescriptor()); if (!checkParameters( methodDescriptor, pattern.parameterSimpleNames, pattern.parameterQualifications, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; } return true; }
private boolean hasStructuralChanges( ClassFileReader reader, TypeStructure existingType, int flags) { if (existingType == null) { return true; } // modifiers if (!modifiersEqual(reader.getModifiers(), existingType.modifiers)) { return true; } // generic signature if (!CharOperation.equals(reader.getGenericSignature(), existingType.genericSignature)) { return true; } // superclass name if (!CharOperation.equals(reader.getSuperclassName(), existingType.superclassName)) { return true; } // class level annotations if ((flags & FLAG_ANNOTATION) != 0) { IBinaryAnnotation[] existingAnnotations = existingType.getAnnotations(); IBinaryAnnotation[] newAnnotations = reader.getAnnotations(); if (!annotationsEqual(existingAnnotations, newAnnotations, flags)) { return true; } } // tag bits; standard annotations like @Deprecated if (reader.getTagBits() != existingType.getTagBits()) { return true; } // interfaces char[][] existingIfs = existingType.interfaces; char[][] newIfsAsChars = reader.getInterfaceNames(); if (newIfsAsChars == null) { newIfsAsChars = EMPTY_CHAR_ARRAY; } // damn I'm lazy... if (existingIfs == null) { existingIfs = EMPTY_CHAR_ARRAY; } if (existingIfs.length != newIfsAsChars.length) return true; new_interface_loop: for (int i = 0; i < newIfsAsChars.length; i++) { for (int j = 0; j < existingIfs.length; j++) { if (CharOperation.equals(existingIfs[j], newIfsAsChars[i])) { continue new_interface_loop; } } return true; } // fields IBinaryField[] newFields = reader.getFields(); if (newFields == null) { newFields = TypeStructure.NoField; } IBinaryField[] existingFs = existingType.binFields; if (newFields.length != existingFs.length) return true; new_field_loop: for (int i = 0; i < newFields.length; i++) { IBinaryField field = newFields[i]; char[] fieldName = field.getName(); for (int j = 0; j < existingFs.length; j++) { if (CharOperation.equals(existingFs[j].getName(), fieldName)) { if (!modifiersEqual(field.getModifiers(), existingFs[j].getModifiers())) { return true; } if (!CharOperation.equals(existingFs[j].getTypeName(), field.getTypeName())) { return true; } if ((flags & FLAG_ANNOTATION) != 0) { if (!annotationsEqual(field.getAnnotations(), existingFs[j].getAnnotations(), flags)) { return true; } } continue new_field_loop; } } return true; } // methods IBinaryMethod[] newMethods = reader.getMethods(); if (newMethods == null) { newMethods = TypeStructure.NoMethod; } char[] fileName = reader.getFileName(); IBinaryMethod[] existingMs = existingType.binMethods; if (newMethods.length != existingMs.length) return true; new_method_loop: for (int i = 0; i < newMethods.length; i++) { IBinaryMethod method = newMethods[i]; char[] methodName = method.getSelector(); for (int j = 0; j < existingMs.length; j++) { if (CharOperation.equals(existingMs[j].getSelector(), methodName)) { // candidate match if (!CharOperation.equals( method.getMethodDescriptor(), existingMs[j].getMethodDescriptor())) { continue; // might be overloading } else { // matching sigs if (!modifiersEqual(method.getModifiers(), existingMs[j].getModifiers())) { return true; } if ((flags & FLAG_ANNOTATION) != 0) { if (!annotationsEqual( method.getAnnotations(), existingMs[j].getAnnotations(), flags)) { return true; } if (!parameterAnnotationsEquals(method, existingMs[j], fileName, flags)) { return true; } } continue new_method_loop; } } } return true; // (no match found) } return false; }
/** Locate declaration in the current class file. This class file is always in a jar. */ public void locateMatches(MatchLocator locator, ClassFile classFile, IBinaryType info) throws CoreException { SearchPattern pattern = locator.pattern; // check annotations references matchAnnotations(pattern, locator, classFile, info); // check class definition BinaryType binaryType = (BinaryType) classFile.getType(); if (matchBinary(pattern, info, null)) { binaryType = new ResolvedBinaryType( (JavaElement) binaryType.getParent(), binaryType.getElementName(), binaryType.getKey()); locator.reportBinaryMemberDeclaration(null, binaryType, null, info, SearchMatch.A_ACCURATE); return; } // Define arrays to store methods/fields from binary type if necessary IBinaryMethod[] binaryMethods = info.getMethods(); int bMethodsLength = binaryMethods == null ? 0 : binaryMethods.length; IBinaryMethod[] unresolvedMethods = null; char[][] binaryMethodSignatures = null; boolean hasUnresolvedMethods = false; // Get fields from binary type info IBinaryField[] binaryFields = info.getFields(); int bFieldsLength = binaryFields == null ? 0 : binaryFields.length; IBinaryField[] unresolvedFields = null; boolean hasUnresolvedFields = false; // Report as many accurate matches as possible int accuracy = SearchMatch.A_ACCURATE; boolean mustResolve = pattern.mustResolve; if (mustResolve) { BinaryTypeBinding binding = locator.cacheBinaryType(binaryType, info); if (binding != null) { // filter out element not in hierarchy scope if (!locator.typeInHierarchy(binding)) return; // Search matches on resolved methods MethodBinding[] availableMethods = binding.availableMethods(); int aMethodsLength = availableMethods == null ? 0 : availableMethods.length; hasUnresolvedMethods = bMethodsLength != aMethodsLength; for (int i = 0; i < aMethodsLength; i++) { MethodBinding method = availableMethods[i]; char[] methodSignature = method.genericSignature(); if (methodSignature == null) methodSignature = method.signature(); // Report the match if possible int level = locator.patternLocator.resolveLevel(method); if (level != PatternLocator.IMPOSSIBLE_MATCH) { IMethod methodHandle = binaryType.getMethod( new String( method.isConstructor() ? binding.compoundName[binding.compoundName.length - 1] : method.selector), CharOperation.toStrings( Signature.getParameterTypes(convertClassFileFormat(methodSignature)))); accuracy = level == PatternLocator.ACCURATE_MATCH ? SearchMatch.A_ACCURATE : SearchMatch.A_INACCURATE; locator.reportBinaryMemberDeclaration(null, methodHandle, method, info, accuracy); } // Remove method from unresolved list if (hasUnresolvedMethods) { if (binaryMethodSignatures == null) { // Store binary method signatures to avoid multiple computation binaryMethodSignatures = new char[bMethodsLength][]; for (int j = 0; j < bMethodsLength; j++) { IBinaryMethod binaryMethod = binaryMethods[j]; char[] signature = binaryMethod.getGenericSignature(); if (signature == null) signature = binaryMethod.getMethodDescriptor(); binaryMethodSignatures[j] = signature; } } for (int j = 0; j < bMethodsLength; j++) { if (CharOperation.equals(binaryMethods[j].getSelector(), method.selector) && CharOperation.equals(binaryMethodSignatures[j], methodSignature)) { if (unresolvedMethods == null) { System.arraycopy( binaryMethods, 0, unresolvedMethods = new IBinaryMethod[bMethodsLength], 0, bMethodsLength); } unresolvedMethods[j] = null; break; } } } } // Search matches on resolved fields FieldBinding[] availableFields = binding.availableFields(); int aFieldsLength = availableFields == null ? 0 : availableFields.length; hasUnresolvedFields = bFieldsLength != aFieldsLength; for (int i = 0; i < aFieldsLength; i++) { FieldBinding field = availableFields[i]; // Report the match if possible int level = locator.patternLocator.resolveLevel(field); if (level != PatternLocator.IMPOSSIBLE_MATCH) { IField fieldHandle = binaryType.getField(new String(field.name)); accuracy = level == PatternLocator.ACCURATE_MATCH ? SearchMatch.A_ACCURATE : SearchMatch.A_INACCURATE; locator.reportBinaryMemberDeclaration(null, fieldHandle, field, info, accuracy); } // Remove the field from unresolved list if (hasUnresolvedFields) { for (int j = 0; j < bFieldsLength; j++) { if (CharOperation.equals(binaryFields[j].getName(), field.name)) { if (unresolvedFields == null) { System.arraycopy( binaryFields, 0, unresolvedFields = new IBinaryField[bFieldsLength], 0, bFieldsLength); } unresolvedFields[j] = null; break; } } } } // If all methods/fields were accurate then returns now if (!hasUnresolvedMethods && !hasUnresolvedFields) { return; } } accuracy = SearchMatch.A_INACCURATE; } // Report inaccurate methods if (mustResolve) binaryMethods = unresolvedMethods; bMethodsLength = binaryMethods == null ? 0 : binaryMethods.length; for (int i = 0; i < bMethodsLength; i++) { IBinaryMethod method = binaryMethods[i]; if (method == null) continue; // impossible match or already reported as accurate if (matchBinary(pattern, method, info)) { char[] name; if (method.isConstructor()) { name = info.getName(); int lastSlash = CharOperation.lastIndexOf('/', name); if (lastSlash != -1) { name = CharOperation.subarray(name, lastSlash + 1, name.length); } } else { name = method.getSelector(); } String selector = new String(name); char[] methodSignature = binaryMethodSignatures == null ? null : binaryMethodSignatures[i]; if (methodSignature == null) { methodSignature = method.getGenericSignature(); if (methodSignature == null) methodSignature = method.getMethodDescriptor(); } String[] parameterTypes = CharOperation.toStrings( Signature.getParameterTypes(convertClassFileFormat(methodSignature))); IMethod methodHandle = binaryType.getMethod(selector, parameterTypes); methodHandle = new ResolvedBinaryMethod(binaryType, selector, parameterTypes, methodHandle.getKey()); locator.reportBinaryMemberDeclaration(null, methodHandle, null, info, accuracy); } } // Report inaccurate fields if (mustResolve) binaryFields = unresolvedFields; bFieldsLength = binaryFields == null ? 0 : binaryFields.length; for (int i = 0; i < bFieldsLength; i++) { IBinaryField field = binaryFields[i]; if (field == null) continue; // impossible match or already reported as accurate if (matchBinary(pattern, field, info)) { String fieldName = new String(field.getName()); IField fieldHandle = binaryType.getField(fieldName); fieldHandle = new ResolvedBinaryField(binaryType, fieldName, fieldHandle.getKey()); locator.reportBinaryMemberDeclaration(null, fieldHandle, null, info, accuracy); } } }