| /******************************************************************************* |
| * 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 |
| * $Id: SuperTypeReferencePattern.java 19915 2009-04-19 17:23:21Z stephan $ |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Fraunhofer FIRST - extended API and implementation |
| * Technical University Berlin - extended API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.core.search.matching; |
| |
| import java.io.IOException; |
| |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.compiler.*; |
| import org.eclipse.jdt.core.search.*; |
| import org.eclipse.jdt.internal.core.index.*; |
| |
| public class SuperTypeReferencePattern extends JavaSearchPattern { |
| |
| public char[] superQualification; |
| public char[] superSimpleName; |
| public char superClassOrInterface; |
| |
| // set to CLASS_SUFFIX for only matching classes |
| // set to INTERFACE_SUFFIX for only matching interfaces |
| // set to TYPE_SUFFIX for matching both classes and interfaces |
| public char typeSuffix; |
| public char[] pkgName; |
| public char[] simpleName; |
| public char[] enclosingTypeName; |
| public char classOrInterface; |
| public int modifiers; |
| public char[][] typeParameterSignatures; |
| |
| protected int superRefKind; |
| public static final int ALL_SUPER_TYPES = 0; |
| public static final int ONLY_SUPER_INTERFACES = 1; // used for IMPLEMENTORS |
| public static final int ONLY_SUPER_CLASSES = 2; // used for hierarchy with a class focus |
| //{ObjectTeams: base class references: |
| public static final int ONLY_BASE_CLASSES = 3; // used for PLAYEDBY_REFERENCES |
| // SH} |
| |
| protected static char[][] CATEGORIES = { SUPER_REF }; |
| |
| public static char[] createIndexKey( |
| int modifiers, |
| char[] packageName, |
| char[] typeName, |
| char[][] enclosingTypeNames, |
| char[][] typeParameterSignatures, |
| char classOrInterface, |
| char[] superTypeName, |
| char superClassOrInterface) { |
| |
| if (superTypeName == null) |
| //{ObjectTeams: needed for generating correct index |
| if (Flags.isTeam(modifiers)) |
| superTypeName = TEAM; |
| else |
| //MW + AK} |
| superTypeName = OBJECT; |
| char[] superSimpleName = CharOperation.lastSegment(superTypeName, '.'); |
| char[] superQualification = null; |
| if (superSimpleName != superTypeName) { |
| int length = superTypeName.length - superSimpleName.length - 1; |
| superQualification = new char[length]; |
| System.arraycopy(superTypeName, 0, superQualification, 0, length); |
| } |
| |
| // if the supertype name contains a $, then split it into: source name and append the $ prefix to the qualification |
| // e.g. p.A$B ---> p.A$ + B |
| char[] superTypeSourceName = CharOperation.lastSegment(superSimpleName, '$'); |
| if (superTypeSourceName != superSimpleName) { |
| int start = superQualification == null ? 0 : superQualification.length + 1; |
| int prefixLength = superSimpleName.length - superTypeSourceName.length; |
| char[] mangledQualification = new char[start + prefixLength]; |
| if (superQualification != null) { |
| System.arraycopy(superQualification, 0, mangledQualification, 0, start-1); |
| mangledQualification[start-1] = '.'; |
| } |
| System.arraycopy(superSimpleName, 0, mangledQualification, start, prefixLength); |
| superQualification = mangledQualification; |
| superSimpleName = superTypeSourceName; |
| } |
| |
| char[] simpleName = CharOperation.lastSegment(typeName, '.'); |
| char[] enclosingTypeName = CharOperation.concatWith(enclosingTypeNames, '$'); |
| if (superQualification != null && CharOperation.equals(superQualification, packageName)) |
| packageName = ONE_ZERO; // save some space |
| |
| char[] typeParameters = CharOperation.NO_CHAR; |
| int typeParametersLength = 0; |
| if (typeParameterSignatures != null) { |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0, length = typeParameterSignatures.length; i < length; i++) { |
| char[] typeParameter = typeParameterSignatures[i]; |
| buffer.append(typeParameter); |
| typeParametersLength += typeParameter.length; |
| if (i != length-1) { |
| buffer.append(','); |
| typeParametersLength++; |
| } |
| } |
| typeParameters = new char[typeParametersLength]; |
| buffer.getChars(0, typeParametersLength, typeParameters, 0); |
| } |
| |
| // superSimpleName / superQualification / simpleName / enclosingTypeName / typeParameters / packageName / superClassOrInterface classOrInterface modifiers |
| int superLength = superSimpleName == null ? 0 : superSimpleName.length; |
| int superQLength = superQualification == null ? 0 : superQualification.length; |
| int simpleLength = simpleName == null ? 0 : simpleName.length; |
| int enclosingLength = enclosingTypeName == null ? 0 : enclosingTypeName.length; |
| int packageLength = packageName == null ? 0 : packageName.length; |
| //{ObjectTeams: one more char for modifiers |
| /* orig: |
| char[] result = new char[superLength + superQLength + simpleLength + enclosingLength + typeParametersLength + packageLength + 9]; |
| :giro */ |
| char[] result = new char[superLength + superQLength + simpleLength + enclosingLength + typeParametersLength + packageLength + 10]; |
| // SH} |
| int pos = 0; |
| if (superLength > 0) { |
| System.arraycopy(superSimpleName, 0, result, pos, superLength); |
| pos += superLength; |
| } |
| result[pos++] = SEPARATOR; |
| if (superQLength > 0) { |
| System.arraycopy(superQualification, 0, result, pos, superQLength); |
| pos += superQLength; |
| } |
| result[pos++] = SEPARATOR; |
| if (simpleLength > 0) { |
| System.arraycopy(simpleName, 0, result, pos, simpleLength); |
| pos += simpleLength; |
| } |
| result[pos++] = SEPARATOR; |
| if (enclosingLength > 0) { |
| System.arraycopy(enclosingTypeName, 0, result, pos, enclosingLength); |
| pos += enclosingLength; |
| } |
| result[pos++] = SEPARATOR; |
| if (typeParametersLength > 0) { |
| System.arraycopy(typeParameters, 0, result, pos, typeParametersLength); |
| pos += typeParametersLength; |
| } |
| result[pos++] = SEPARATOR; |
| if (packageLength > 0) { |
| System.arraycopy(packageName, 0, result, pos, packageLength); |
| pos += packageLength; |
| } |
| result[pos++] = SEPARATOR; |
| result[pos++] = superClassOrInterface; |
| result[pos++] = classOrInterface; |
| //{ObjectTeams: expand to also cover AccRole: |
| /* orig: |
| result[pos] = (char) modifiers; |
| :giro */ |
| result[pos++] = (char) modifiers; |
| result[pos] = (char) (modifiers>>16); |
| // SH} |
| return result; |
| } |
| |
| public SuperTypeReferencePattern( |
| char[] superQualification, |
| char[] superSimpleName, |
| int superRefKind, |
| int matchRule) { |
| |
| this(matchRule); |
| |
| this.superQualification = this.isCaseSensitive ? superQualification : CharOperation.toLowerCase(superQualification); |
| this.superSimpleName = (this.isCaseSensitive || this.isCamelCase) ? superSimpleName : CharOperation.toLowerCase(superSimpleName); |
| this.mustResolve = superQualification != null; |
| this.superRefKind = superRefKind; |
| } |
| public SuperTypeReferencePattern( |
| char[] superQualification, |
| char[] superSimpleName, |
| int superRefKind, |
| char typeSuffix, |
| int matchRule) { |
| |
| this(superQualification, superSimpleName, superRefKind, matchRule); |
| this.typeSuffix = typeSuffix; |
| this.mustResolve = superQualification != null || typeSuffix != TYPE_SUFFIX; |
| } |
| SuperTypeReferencePattern(int matchRule) { |
| super(SUPER_REF_PATTERN, matchRule); |
| } |
| /* |
| * superSimpleName / superQualification / simpleName / enclosingTypeName / typeParameters / pkgName / superClassOrInterface classOrInterface modifiers |
| */ |
| public void decodeIndexKey(char[] key) { |
| int slash = CharOperation.indexOf(SEPARATOR, key, 0); |
| this.superSimpleName = CharOperation.subarray(key, 0, slash); |
| |
| // some values may not have been know when indexed so decode as null |
| int start = slash + 1; |
| slash = CharOperation.indexOf(SEPARATOR, key, start); |
| this.superQualification = slash == start ? null : CharOperation.subarray(key, start, slash); |
| |
| slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1); |
| this.simpleName = CharOperation.subarray(key, start, slash); |
| |
| start = ++slash; |
| if (key[start] == SEPARATOR) { |
| this.enclosingTypeName = null; |
| } else { |
| slash = CharOperation.indexOf(SEPARATOR, key, start); |
| if (slash == (start+1) && key[start] == ZERO_CHAR) { |
| this.enclosingTypeName = ONE_ZERO; |
| } else { |
| char[] names = CharOperation.subarray(key, start, slash); |
| this.enclosingTypeName = names; |
| } |
| } |
| |
| start = ++slash; |
| if (key[start] == SEPARATOR) { |
| this.typeParameterSignatures = null; |
| } else { |
| slash = CharOperation.indexOf(SEPARATOR, key, start); |
| this.typeParameterSignatures = CharOperation.splitOn(',', key, start, slash); |
| } |
| |
| start = ++slash; |
| if (key[start] == SEPARATOR) { |
| this.pkgName = null; |
| } else { |
| slash = CharOperation.indexOf(SEPARATOR, key, start); |
| if (slash == (start+1) && key[start] == ZERO_CHAR) { |
| this.pkgName = this.superQualification; |
| } else { |
| char[] names = CharOperation.subarray(key, start, slash); |
| this.pkgName = names; |
| } |
| } |
| |
| this.superClassOrInterface = key[slash + 1]; |
| this.classOrInterface = key[slash + 2]; |
| //{ObjectTeams: expanded to also cover AccRole: |
| /* orig: |
| this.modifiers = key[slash + 3]; // implicit cast to int type |
| :giro */ |
| this.modifiers = key[slash + 3] + (key[slash + 4]<<16); |
| // SH} |
| } |
| public SearchPattern getBlankPattern() { |
| return new SuperTypeReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE); |
| } |
| public char[][] getIndexCategories() { |
| return CATEGORIES; |
| } |
| public boolean matchesDecodedKey(SearchPattern decodedPattern) { |
| SuperTypeReferencePattern pattern = (SuperTypeReferencePattern) decodedPattern; |
| if (this.superRefKind == ONLY_SUPER_CLASSES && pattern.enclosingTypeName != ONE_ZERO/*not an anonymous*/) |
| // consider enumerations as classes, reject interfaces and annotations |
| if (pattern.superClassOrInterface == INTERFACE_SUFFIX |
| || pattern.superClassOrInterface == ANNOTATION_TYPE_SUFFIX) |
| return false; |
| //{ObjectTeams: don't mix baseclass and super references |
| if ((this.superRefKind == ONLY_BASE_CLASSES) != (pattern.superClassOrInterface == BASECLASS_SUFFIX)) |
| return false; |
| // SH} |
| |
| if (pattern.superQualification != null) |
| if (!matchesName(this.superQualification, pattern.superQualification)) return false; |
| |
| return matchesName(this.superSimpleName, pattern.superSimpleName); |
| } |
| public EntryResult[] queryIn(Index index) throws IOException { |
| char[] key = this.superSimpleName; // can be null |
| int matchRule = getMatchRule(); |
| |
| // cannot include the superQualification since it may not exist in the index |
| switch(getMatchMode()) { |
| case R_EXACT_MATCH : |
| // do a prefix query with the superSimpleName |
| matchRule &= ~R_EXACT_MATCH; |
| matchRule |= R_PREFIX_MATCH; |
| if (this.superSimpleName != null) |
| key = CharOperation.append(this.superSimpleName, SEPARATOR); |
| break; |
| case R_PREFIX_MATCH : |
| // do a prefix query with the superSimpleName |
| break; |
| case R_PATTERN_MATCH : |
| // do a pattern query with the superSimpleName |
| break; |
| case R_REGEXP_MATCH : |
| // TODO (frederic) implement regular expression match |
| break; |
| case R_CAMELCASE_MATCH: |
| case R_CAMELCASE_SAME_PART_COUNT_MATCH: |
| // do a prefix query with the superSimpleName |
| break; |
| } |
| |
| return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null |
| } |
| protected StringBuffer print(StringBuffer output) { |
| switch (this.superRefKind) { |
| case ALL_SUPER_TYPES: |
| output.append("SuperTypeReferencePattern: <"); //$NON-NLS-1$ |
| break; |
| case ONLY_SUPER_INTERFACES: |
| output.append("SuperInterfaceReferencePattern: <"); //$NON-NLS-1$ |
| break; |
| case ONLY_SUPER_CLASSES: |
| output.append("SuperClassReferencePattern: <"); //$NON-NLS-1$ |
| break; |
| //{ObjectTeams: base classes: |
| case ONLY_BASE_CLASSES: |
| output.append("BaseClassReferencePattern: <"); //$NON-NLS-1$ |
| break; |
| // SH} |
| } |
| if (this.superSimpleName != null) |
| output.append(this.superSimpleName); |
| else |
| output.append("*"); //$NON-NLS-1$ |
| output.append(">"); //$NON-NLS-1$ |
| return super.print(output); |
| } |
| } |