public SearchMatch newDeclarationMatch( ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, int length, MatchLocator locator) { if (elementBinding != null) { MethodBinding methodBinding = (MethodBinding) elementBinding; // If method parameters verification was not valid, then try to see if method arguments can // match a method in hierarchy if (this.methodDeclarationsWithInvalidParam.containsKey(reference)) { // First see if this reference has already been resolved => report match if validated Boolean report = (Boolean) this.methodDeclarationsWithInvalidParam.get(reference); if (report != null) { if (report.booleanValue()) { return super.newDeclarationMatch( reference, element, elementBinding, accuracy, length, locator); } return null; } if (matchOverriddenMethod(methodBinding.declaringClass, methodBinding, null)) { this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE); return super.newDeclarationMatch( reference, element, elementBinding, accuracy, length, locator); } if (isTypeInSuperDeclaringTypeNames(methodBinding.declaringClass.compoundName)) { MethodBinding patternBinding = locator.getMethodBinding(this.pattern); if (patternBinding != null) { if (!matchOverriddenMethod( patternBinding.declaringClass, patternBinding, methodBinding)) { this.methodDeclarationsWithInvalidParam.put(reference, Boolean.FALSE); return null; } } this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE); return super.newDeclarationMatch( reference, element, elementBinding, accuracy, length, locator); } this.methodDeclarationsWithInvalidParam.put(reference, Boolean.FALSE); return null; } } return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator); }
protected void reportDeclaration( MethodBinding methodBinding, MatchLocator locator, SimpleSet knownMethods) throws CoreException { ReferenceBinding declaringClass = methodBinding.declaringClass; IType type = locator.lookupType(declaringClass); if (type == null) return; // case of a secondary type // Report match for binary if (type.isBinary()) { IMethod method = null; TypeBinding[] parameters = methodBinding.original().parameters; int parameterLength = parameters.length; char[][] parameterTypes = new char[parameterLength][]; for (int i = 0; i < parameterLength; i++) { char[] typeName = parameters[i].qualifiedSourceName(); for (int j = 0, dim = parameters[i].dimensions(); j < dim; j++) { typeName = CharOperation.concat(typeName, new char[] {'[', ']'}); } parameterTypes[i] = typeName; } method = locator.createBinaryMethodHandle(type, methodBinding.selector, parameterTypes); if (method == null || knownMethods.addIfNotIncluded(method) == null) return; IResource resource = type.getResource(); if (resource == null) resource = type.getJavaProject().getProject(); IBinaryType info = locator.getBinaryInfo( (org.eclipse.jdt.internal.core.ClassFile) type.getClassFile(), resource); locator.reportBinaryMemberDeclaration( resource, method, methodBinding, info, SearchMatch.A_ACCURATE); return; } // When source is available, report match if method is found in the declaring type IResource resource = type.getResource(); if (declaringClass instanceof ParameterizedTypeBinding) declaringClass = ((ParameterizedTypeBinding) declaringClass).genericType(); ClassScope scope = ((SourceTypeBinding) declaringClass).scope; if (scope != null) { TypeDeclaration typeDecl = scope.referenceContext; AbstractMethodDeclaration methodDecl = typeDecl.declarationOf(methodBinding.original()); if (methodDecl != null) { // Create method handle from method declaration String methodName = new String(methodBinding.selector); Argument[] arguments = methodDecl.arguments; int length = arguments == null ? 0 : arguments.length; String[] parameterTypes = new String[length]; for (int i = 0; i < length; i++) { char[][] typeName = arguments[i].type.getParameterizedTypeName(); parameterTypes[i] = Signature.createTypeSignature(CharOperation.concatWith(typeName, '.'), false); } IMethod method = type.getMethod(methodName, parameterTypes); if (method == null || knownMethods.addIfNotIncluded(method) == null) return; // Create and report corresponding match int offset = methodDecl.sourceStart; this.match = new MethodDeclarationMatch( method, SearchMatch.A_ACCURATE, offset, methodDecl.sourceEnd - offset + 1, locator.getParticipant(), resource); locator.report(this.match); } } }
void matchReportReference( MessageSend messageSend, MatchLocator locator, MethodBinding methodBinding) throws CoreException { // Look if there's a need to special report for parameterized type boolean isParameterized = false; if (methodBinding instanceof ParameterizedGenericMethodBinding) { // parameterized generic method isParameterized = true; // Update match regarding method type arguments ParameterizedGenericMethodBinding parameterizedMethodBinding = (ParameterizedGenericMethodBinding) methodBinding; this.match.setRaw(parameterizedMethodBinding.isRaw); TypeBinding[] typeArguments = /*parameterizedMethodBinding.isRaw ? null :*/ parameterizedMethodBinding.typeArguments; updateMatch( typeArguments, locator, this.pattern.methodArguments, this.pattern.hasMethodParameters()); // Update match regarding declaring class type arguments if (methodBinding.declaringClass.isParameterizedType() || methodBinding.declaringClass.isRawType()) { ParameterizedTypeBinding parameterizedBinding = (ParameterizedTypeBinding) methodBinding.declaringClass; if (!this.pattern.hasTypeArguments() && this.pattern.hasMethodArguments() || parameterizedBinding.isParameterizedWithOwnVariables()) { // special case for pattern which defines method arguments but not its declaring type // in this case, we do not refine accuracy using declaring type arguments...! } else { updateMatch( parameterizedBinding, this.pattern.getTypeArguments(), this.pattern.hasTypeParameters(), 0, locator); } } else if (this.pattern.hasTypeArguments()) { this.match.setRule(SearchPattern.R_ERASURE_MATCH); } // Update match regarding method parameters // TODO ? (frederic) // Update match regarding method return type // TODO ? (frederic) // Special case for errors if (this.match.getRule() != 0 && messageSend.resolvedType == null) { this.match.setRule(SearchPattern.R_ERASURE_MATCH); } } else if (methodBinding instanceof ParameterizedMethodBinding) { isParameterized = true; if (methodBinding.declaringClass.isParameterizedType() || methodBinding.declaringClass.isRawType()) { ParameterizedTypeBinding parameterizedBinding = (ParameterizedTypeBinding) methodBinding.declaringClass; if (!parameterizedBinding.isParameterizedWithOwnVariables()) { updateMatch( parameterizedBinding, this.pattern.getTypeArguments(), this.pattern.hasTypeParameters(), 0, locator); } } else if (this.pattern.hasTypeArguments()) { this.match.setRule(SearchPattern.R_ERASURE_MATCH); } // Update match regarding method parameters // TODO ? (frederic) // Update match regarding method return type // TODO ? (frederic) // Special case for errors if (this.match.getRule() != 0 && messageSend.resolvedType == null) { this.match.setRule(SearchPattern.R_ERASURE_MATCH); } } else if (this.pattern .hasMethodArguments()) { // binding has no type params, compatible erasure if pattern does this.match.setRule(SearchPattern.R_ERASURE_MATCH); } // See whether it is necessary to report or not if (this.match.getRule() == 0) return; // impossible match boolean report = (this.isErasureMatch && this.match.isErasure()) || (this.isEquivalentMatch && this.match.isEquivalent()) || this.match.isExact(); if (!report) return; // Report match int offset = (int) (messageSend.nameSourcePosition >>> 32); this.match.setOffset(offset); this.match.setLength(messageSend.sourceEnd - offset + 1); if (isParameterized && this.pattern.hasMethodArguments()) { locator.reportAccurateParameterizedMethodReference( this.match, messageSend, messageSend.typeArguments); } else { locator.report(this.match); } }
/** * @see * org.eclipse.jdt.internal.core.search.matching.PatternLocator#matchReportReference(org.eclipse.jdt.internal.compiler.ast.ASTNode, * org.eclipse.jdt.core.IJavaElement, Binding, int, * org.eclipse.jdt.internal.core.search.matching.MatchLocator) */ protected void matchReportReference( ASTNode reference, IJavaElement element, IJavaElement localElement, IJavaElement[] otherElements, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException { MethodBinding methodBinding = (reference instanceof MessageSend) ? ((MessageSend) reference).binding : ((elementBinding instanceof MethodBinding) ? (MethodBinding) elementBinding : null); if (this.isDeclarationOfReferencedMethodsPattern) { if (methodBinding == null) return; // need exact match to be able to open on type ref if (accuracy != SearchMatch.A_ACCURATE) return; // element that references the method must be included in the enclosing element DeclarationOfReferencedMethodsPattern declPattern = (DeclarationOfReferencedMethodsPattern) this.pattern; while (element != null && !declPattern.enclosingElement.equals(element)) element = element.getParent(); if (element != null) { reportDeclaration(methodBinding, locator, declPattern.knownMethods); } } else { MethodReferenceMatch methodReferenceMatch = locator.newMethodReferenceMatch( element, elementBinding, accuracy, -1, -1, false /*not constructor*/, false /*not synthetic*/, reference); methodReferenceMatch.setLocalElement(localElement); this.match = methodReferenceMatch; if (this.pattern.findReferences && reference instanceof MessageSend) { IJavaElement focus = this.pattern.focus; // verify closest match if pattern was bound // (see bug 70827) if (focus != null && focus.getElementType() == IJavaElement.METHOD) { if (methodBinding != null && methodBinding.declaringClass != null) { boolean isPrivate = Flags.isPrivate(((IMethod) focus).getFlags()); if (isPrivate && !CharOperation.equals( methodBinding.declaringClass.sourceName, focus.getParent().getElementName().toCharArray())) { return; // finally the match was not possible } } } matchReportReference((MessageSend) reference, locator, ((MessageSend) reference).binding); } else { if (reference instanceof SingleMemberAnnotation) { reference = ((SingleMemberAnnotation) reference).memberValuePairs()[0]; this.match.setImplicit(true); } int offset = reference.sourceStart; int length = reference.sourceEnd - offset + 1; this.match.setOffset(offset); this.match.setLength(length); locator.report(this.match); } } }
/* * Look for annotations references */ private void matchAnnotations( SearchPattern pattern, MatchLocator locator, ClassFile classFile, IBinaryType binaryType) throws CoreException { // Only process TypeReference patterns switch (pattern.kind) { case TYPE_REF_PATTERN: break; case OR_PATTERN: SearchPattern[] patterns = ((OrPattern) pattern).patterns; for (int i = 0, length = patterns.length; i < length; i++) { matchAnnotations(patterns[i], locator, classFile, binaryType); } // $FALL-THROUGH$ - fall through default to return default: return; } TypeReferencePattern typeReferencePattern = (TypeReferencePattern) pattern; // Look for references in class annotations IBinaryAnnotation[] annotations = binaryType.getAnnotations(); BinaryType classFileBinaryType = (BinaryType) classFile.getType(); BinaryTypeBinding binaryTypeBinding = null; if (checkAnnotations(typeReferencePattern, annotations, binaryType.getTagBits())) { classFileBinaryType = new ResolvedBinaryType( (JavaElement) classFileBinaryType.getParent(), classFileBinaryType.getElementName(), classFileBinaryType.getKey()); TypeReferenceMatch match = new TypeReferenceMatch( classFileBinaryType, SearchMatch.A_ACCURATE, -1, 0, false, locator.getParticipant(), locator.currentPossibleMatch.resource); // TODO 3.4 M7 (frederic) - bug 209996: see how create the annotation handle from the binary // and put it in the local element match.setLocalElement(null); locator.report(match); } // Look for references in methods annotations MethodInfo[] methods = (MethodInfo[]) binaryType.getMethods(); if (methods != null) { for (int i = 0, max = methods.length; i < max; i++) { MethodInfo method = methods[i]; if (checkAnnotations(typeReferencePattern, method.getAnnotations(), method.getTagBits())) { binaryTypeBinding = locator.cacheBinaryType(classFileBinaryType, binaryType); IMethod methodHandle = classFileBinaryType.getMethod( new String( method.isConstructor() ? binaryTypeBinding .compoundName[binaryTypeBinding.compoundName.length - 1] : method.getSelector()), CharOperation.toStrings( Signature.getParameterTypes( convertClassFileFormat(method.getMethodDescriptor())))); TypeReferenceMatch match = new TypeReferenceMatch( methodHandle, SearchMatch.A_ACCURATE, -1, 0, false, locator.getParticipant(), locator.currentPossibleMatch.resource); // TODO 3.4 M7 (frederic) - bug 209996: see how create the annotation handle from the // binary and put it in the local element match.setLocalElement(null); locator.report(match); } } } // Look for references in fields annotations FieldInfo[] fields = (FieldInfo[]) binaryType.getFields(); if (fields != null) { for (int i = 0, max = fields.length; i < max; i++) { FieldInfo field = fields[i]; if (checkAnnotations(typeReferencePattern, field.getAnnotations(), field.getTagBits())) { IField fieldHandle = classFileBinaryType.getField(new String(field.getName())); TypeReferenceMatch match = new TypeReferenceMatch( fieldHandle, SearchMatch.A_ACCURATE, -1, 0, false, locator.getParticipant(), locator.currentPossibleMatch.resource); // TODO 3.4 M7 (frederic) - bug 209996: see how create the annotation handle from the // binary and put it in the local element match.setLocalElement(null); locator.report(match); } } } }
/** 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); } } }