/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.core.search.matching; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.search.SearchMatch; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.TypeReferenceMatch; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.classfmt.FieldInfo; import org.eclipse.jdt.internal.compiler.classfmt.MethodInfo; import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; import org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair; import org.eclipse.jdt.internal.compiler.env.IBinaryField; import org.eclipse.jdt.internal.compiler.env.IBinaryMethod; import org.eclipse.jdt.internal.compiler.env.IBinaryType; import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.core.BinaryType; import org.eclipse.jdt.internal.core.ClassFile; import org.eclipse.jdt.internal.core.JavaElement; import org.eclipse.jdt.internal.core.ResolvedBinaryField; import org.eclipse.jdt.internal.core.ResolvedBinaryMethod; import org.eclipse.jdt.internal.core.ResolvedBinaryType; import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants; public class ClassFileMatchLocator implements IIndexConstants { private static final long TARGET_ANNOTATION_BITS= TagBits.AnnotationForType | TagBits.AnnotationForParameter | TagBits.AnnotationForPackage | TagBits.AnnotationForMethod | TagBits.AnnotationForLocalVariable | TagBits.AnnotationForField | TagBits.AnnotationForConstructor | TagBits.AnnotationForAnnotationType; private static final char[] JAVA_LANG_ANNOTATION_ELEMENTTYPE= CharOperation.concatWith(TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE, '.'); public static char[] convertClassFileFormat(char[] name) { return CharOperation.replaceOnCopy(name, '/', '.'); } private boolean checkAnnotation(IBinaryAnnotation annotation, TypeReferencePattern pattern) { if (checkTypeName(pattern.simpleName, pattern.qualification, convertClassFileFormat(Signature.toCharArray(annotation.getTypeName())), pattern.isCaseSensitive, pattern.isCamelCase)) { return true; } IBinaryElementValuePair[] valuePairs= annotation.getElementValuePairs(); if (valuePairs != null) { for (int j= 0, vpLength= valuePairs.length; j < vpLength; j++) { IBinaryElementValuePair valuePair= valuePairs[j]; Object pairValue= valuePair.getValue(); if (pairValue instanceof IBinaryAnnotation) { if (checkAnnotation((IBinaryAnnotation)pairValue, pattern)) { return true; } } } } return false; } private boolean checkAnnotations(TypeReferencePattern pattern, IBinaryAnnotation[] annotations, long tagBits) { if (annotations != null) { for (int a= 0, length= annotations.length; a < length; a++) { IBinaryAnnotation annotation= annotations[a]; if (checkAnnotation(annotation, pattern)) { return true; } } } if ((tagBits & TagBits.AllStandardAnnotationsMask) != 0 && checkStandardAnnotations(tagBits, pattern)) { return true; } return false; } private boolean checkAnnotationTypeReference(char[] fullyQualifiedName, TypeReferencePattern pattern) { return checkTypeName(pattern.simpleName, pattern.qualification, fullyQualifiedName, pattern.isCaseSensitive, pattern.isCamelCase); } private boolean checkDeclaringType(IBinaryType enclosingBinaryType, char[] simpleName, char[] qualification, boolean isCaseSensitive, boolean isCamelCase) { if (simpleName == null && qualification == null) return true; if (enclosingBinaryType == null) return true; char[] declaringTypeName= convertClassFileFormat(enclosingBinaryType.getName()); return checkTypeName(simpleName, qualification, declaringTypeName, isCaseSensitive, isCamelCase); } private boolean checkParameters(char[] methodDescriptor, char[][] parameterSimpleNames, char[][] parameterQualifications, boolean isCaseSensitive, boolean isCamelCase) { char[][] arguments= Signature.getParameterTypes(methodDescriptor); int parameterCount= parameterSimpleNames.length; if (parameterCount != arguments.length) return false; for (int i= 0; i < parameterCount; i++) if (!checkTypeName(parameterSimpleNames[i], parameterQualifications[i], Signature.toCharArray(arguments[i]), isCaseSensitive, isCamelCase)) return false; return true; } private boolean checkStandardAnnotations(long annotationTagBits, TypeReferencePattern pattern) { if ((annotationTagBits & TagBits.AnnotationTargetMASK) != 0) { char[][] compoundName= TypeConstants.JAVA_LANG_ANNOTATION_TARGET; if (checkAnnotationTypeReference(CharOperation.concatWith(compoundName, '.'), pattern) || ((annotationTagBits & TARGET_ANNOTATION_BITS) != 0 && checkAnnotationTypeReference(JAVA_LANG_ANNOTATION_ELEMENTTYPE, pattern))) { return true; } } if ((annotationTagBits & TagBits.AnnotationRetentionMASK) != 0) { char[][] compoundName= TypeConstants.JAVA_LANG_ANNOTATION_RETENTION; if (checkAnnotationTypeReference(CharOperation.concatWith(compoundName, '.'), pattern) || checkAnnotationTypeReference(CharOperation.concatWith(TypeConstants.JAVA_LANG_ANNOTATION_RETENTIONPOLICY, '.'), pattern)) { return true; } } if ((annotationTagBits & TagBits.AnnotationDeprecated) != 0) { char[][] compoundName= TypeConstants.JAVA_LANG_DEPRECATED; if (checkAnnotationTypeReference(CharOperation.concatWith(compoundName, '.'), pattern)) { return true; } } if ((annotationTagBits & TagBits.AnnotationDocumented) != 0) { char[][] compoundName= TypeConstants.JAVA_LANG_ANNOTATION_DOCUMENTED; if (checkAnnotationTypeReference(CharOperation.concatWith(compoundName, '.'), pattern)) { return true; } } if ((annotationTagBits & TagBits.AnnotationInherited) != 0) { char[][] compoundName= TypeConstants.JAVA_LANG_ANNOTATION_INHERITED; if (checkAnnotationTypeReference(CharOperation.concatWith(compoundName, '.'), pattern)) { return true; } } if ((annotationTagBits & TagBits.AnnotationOverride) != 0) { char[][] compoundName= TypeConstants.JAVA_LANG_OVERRIDE; if (checkAnnotationTypeReference(CharOperation.concatWith(compoundName, '.'), pattern)) { return true; } } if ((annotationTagBits & TagBits.AnnotationSuppressWarnings) != 0) { char[][] compoundName= TypeConstants.JAVA_LANG_SUPPRESSWARNINGS; if (checkAnnotationTypeReference(CharOperation.concatWith(compoundName, '.'), pattern)) { return true; } } return false; } private boolean checkTypeName(char[] simpleName, char[] qualification, char[] fullyQualifiedTypeName, boolean isCaseSensitive, boolean isCamelCase) { // NOTE: if case insensitive then simpleName & qualification are assumed to be lowercase char[] wildcardPattern= PatternLocator.qualifiedPattern(simpleName, qualification); if (wildcardPattern == null) return true; return CharOperation.match(wildcardPattern, fullyQualifiedTypeName, isCaseSensitive); } /** * 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); } } } /* * 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); } } } } /** * Finds out whether the given binary info matches the search pattern. Default is to return * false. */ boolean matchBinary(SearchPattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) { switch (pattern.kind) { case CONSTRUCTOR_PATTERN: return matchConstructor((ConstructorPattern)pattern, binaryInfo, enclosingBinaryType); case FIELD_PATTERN: return matchField((FieldPattern)pattern, binaryInfo, enclosingBinaryType); case METHOD_PATTERN: return matchMethod((MethodPattern)pattern, binaryInfo, enclosingBinaryType); case SUPER_REF_PATTERN: return matchSuperTypeReference((SuperTypeReferencePattern)pattern, binaryInfo, enclosingBinaryType); case TYPE_DECL_PATTERN: return matchTypeDeclaration((TypeDeclarationPattern)pattern, binaryInfo, enclosingBinaryType); case OR_PATTERN: SearchPattern[] patterns= ((OrPattern)pattern).patterns; for (int i= 0, length= patterns.length; i < length; i++) if (matchBinary(patterns[i], binaryInfo, enclosingBinaryType)) return true; } return false; } 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; } boolean matchField(FieldPattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) { if (!pattern.findDeclarations) return false; // only relevant when finding declarations if (!(binaryInfo instanceof IBinaryField)) return false; IBinaryField field= (IBinaryField)binaryInfo; if (!pattern.matchesName(pattern.name, field.getName())) return false; if (!checkDeclaringType(enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; char[] fieldTypeSignature= Signature.toCharArray(convertClassFileFormat(field.getTypeName())); return checkTypeName(pattern.typeSimpleName, pattern.typeQualification, fieldTypeSignature, pattern.isCaseSensitive(), pattern.isCamelCase()); } 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 matchSuperTypeReference(SuperTypeReferencePattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) { if (!(binaryInfo instanceof IBinaryType)) return false; IBinaryType type= (IBinaryType)binaryInfo; if (pattern.superRefKind != SuperTypeReferencePattern.ONLY_SUPER_INTERFACES) { char[] vmName= type.getSuperclassName(); if (vmName != null) { char[] superclassName= convertClassFileFormat(vmName); if (checkTypeName(pattern.superSimpleName, pattern.superQualification, superclassName, pattern.isCaseSensitive(), pattern.isCamelCase())) return true; } } if (pattern.superRefKind != SuperTypeReferencePattern.ONLY_SUPER_CLASSES) { char[][] superInterfaces= type.getInterfaceNames(); if (superInterfaces != null) { for (int i= 0, max= superInterfaces.length; i < max; i++) { char[] superInterfaceName= convertClassFileFormat(superInterfaces[i]); if (checkTypeName(pattern.superSimpleName, pattern.superQualification, superInterfaceName, pattern.isCaseSensitive(), pattern.isCamelCase())) return true; } } } return false; } boolean matchTypeDeclaration(TypeDeclarationPattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) { if (!(binaryInfo instanceof IBinaryType)) return false; IBinaryType type= (IBinaryType)binaryInfo; char[] fullyQualifiedTypeName= convertClassFileFormat(type.getName()); boolean qualifiedPattern= pattern instanceof QualifiedTypeDeclarationPattern; if (pattern.enclosingTypeNames == null || qualifiedPattern) { char[] simpleName= (pattern.getMatchMode() == SearchPattern.R_PREFIX_MATCH) ? CharOperation.concat(pattern.simpleName, IIndexConstants.ONE_STAR) : pattern.simpleName; char[] pkg= qualifiedPattern ? ((QualifiedTypeDeclarationPattern)pattern).qualification : pattern.pkg; if (!checkTypeName(simpleName, pkg, fullyQualifiedTypeName, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; } else { char[] enclosingTypeName= CharOperation.concatWith(pattern.enclosingTypeNames, '.'); char[] patternString= pattern.pkg == null ? enclosingTypeName : CharOperation.concat(pattern.pkg, enclosingTypeName, '.'); if (!checkTypeName(pattern.simpleName, patternString, fullyQualifiedTypeName, pattern.isCaseSensitive(), pattern.isCamelCase())) return false; } int kind= TypeDeclaration.kind(type.getModifiers()); switch (pattern.typeSuffix) { case CLASS_SUFFIX: return kind == TypeDeclaration.CLASS_DECL; case INTERFACE_SUFFIX: return kind == TypeDeclaration.INTERFACE_DECL; case ENUM_SUFFIX: return kind == TypeDeclaration.ENUM_DECL; case ANNOTATION_TYPE_SUFFIX: return kind == TypeDeclaration.ANNOTATION_TYPE_DECL; case CLASS_AND_INTERFACE_SUFFIX: return kind == TypeDeclaration.CLASS_DECL || kind == TypeDeclaration.INTERFACE_DECL; case CLASS_AND_ENUM_SUFFIX: return kind == TypeDeclaration.CLASS_DECL || kind == TypeDeclaration.ENUM_DECL; case INTERFACE_AND_ANNOTATION_SUFFIX: return kind == TypeDeclaration.INTERFACE_DECL || kind == TypeDeclaration.ANNOTATION_TYPE_DECL; case TYPE_SUFFIX: // nothing } return true; } }