001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core.search.matching;
011:
012: import java.io.IOException;
013:
014: import org.eclipse.jdt.core.compiler.CharOperation;
015: import org.eclipse.jdt.core.search.SearchPattern;
016: import org.eclipse.jdt.internal.core.index.*;
017:
018: public class MultiTypeDeclarationPattern extends JavaSearchPattern {
019:
020: public char[][] simpleNames;
021: public char[][] qualifications;
022:
023: // set to CLASS_SUFFIX for only matching classes
024: // set to INTERFACE_SUFFIX for only matching interfaces
025: // set to ENUM_SUFFIX for only matching enums
026: // set to ANNOTATION_TYPE_SUFFIX for only matching annotation types
027: // set to TYPE_SUFFIX for matching both classes and interfaces
028: public char typeSuffix;
029:
030: protected static char[][] CATEGORIES = { TYPE_DECL };
031:
032: public MultiTypeDeclarationPattern(char[][] qualifications,
033: char[][] simpleNames, char typeSuffix, int matchRule) {
034:
035: this (matchRule);
036:
037: if (isCaseSensitive() || qualifications == null) {
038: this .qualifications = qualifications;
039: } else {
040: int length = qualifications.length;
041: this .qualifications = new char[length][];
042: for (int i = 0; i < length; i++)
043: this .qualifications[i] = CharOperation
044: .toLowerCase(qualifications[i]);
045: }
046: // null simple names are allowed (should return all names)
047: if (simpleNames != null) {
048: if (this .isCaseSensitive || this .isCamelCase) {
049: this .simpleNames = simpleNames;
050: } else {
051: int length = simpleNames.length;
052: this .simpleNames = new char[length][];
053: for (int i = 0; i < length; i++)
054: this .simpleNames[i] = CharOperation
055: .toLowerCase(simpleNames[i]);
056: }
057: }
058: this .typeSuffix = typeSuffix;
059:
060: ((InternalSearchPattern) this ).mustResolve = typeSuffix != TYPE_SUFFIX; // only used to report type declarations, not their positions
061: }
062:
063: MultiTypeDeclarationPattern(int matchRule) {
064: super (TYPE_DECL_PATTERN, matchRule);
065: }
066:
067: public SearchPattern getBlankPattern() {
068: return new QualifiedTypeDeclarationPattern(R_EXACT_MATCH
069: | R_CASE_SENSITIVE);
070: }
071:
072: public char[][] getIndexCategories() {
073: return CATEGORIES;
074: }
075:
076: public boolean matchesDecodedKey(SearchPattern decodedPattern) {
077: QualifiedTypeDeclarationPattern pattern = (QualifiedTypeDeclarationPattern) decodedPattern;
078:
079: // check type suffix
080: if (this .typeSuffix != pattern.typeSuffix
081: && typeSuffix != TYPE_SUFFIX) {
082: if (!matchDifferentTypeSuffixes(this .typeSuffix,
083: pattern.typeSuffix)) {
084: return false;
085: }
086: }
087:
088: // check qualified name
089: if (this .qualifications != null) {
090: int count = 0;
091: int max = this .qualifications.length;
092: if (max == 0 && pattern.qualification.length > 0) {
093: return false;
094: }
095: if (max > 0) {
096: for (; count < max; count++)
097: if (matchesName(this .qualifications[count],
098: pattern.qualification))
099: break;
100: if (count == max)
101: return false;
102: }
103: }
104:
105: // check simple name (null are allowed)
106: if (this .simpleNames == null)
107: return true;
108: int count = 0;
109: int max = this .simpleNames.length;
110: for (; count < max; count++)
111: if (matchesName(this .simpleNames[count], pattern.simpleName))
112: break;
113: return count < max;
114: }
115:
116: EntryResult[] queryIn(Index index) throws IOException {
117: if (this .simpleNames == null) {
118: // if no simple names then return all possible ones from index
119: return index.query(getIndexCategories(), null, -1); // match rule is irrelevant when the key is null
120: }
121:
122: int count = -1;
123: int numOfNames = this .simpleNames.length;
124: EntryResult[][] allResults = numOfNames > 1 ? new EntryResult[numOfNames][]
125: : null;
126: for (int i = 0; i < numOfNames; i++) {
127: char[] key = this .simpleNames[i];
128: int matchRule = getMatchRule();
129:
130: switch (getMatchMode()) {
131: case R_PREFIX_MATCH:
132: // do a prefix query with the simpleName
133: break;
134: case R_EXACT_MATCH:
135: if (!this .isCamelCase) {
136: // do a prefix query with the simpleName
137: matchRule &= ~R_EXACT_MATCH;
138: matchRule |= R_PREFIX_MATCH;
139: key = CharOperation.append(key, SEPARATOR);
140: }
141: break;
142: case R_PATTERN_MATCH:
143: if (key[key.length - 1] != '*')
144: key = CharOperation
145: .concat(key, ONE_STAR, SEPARATOR);
146: break;
147: case R_REGEXP_MATCH:
148: // TODO (frederic) implement regular expression match
149: break;
150: }
151:
152: EntryResult[] entries = index.query(getIndexCategories(),
153: key, matchRule); // match rule is irrelevant when the key is null
154: if (entries != null) {
155: if (allResults == null)
156: return entries;
157: allResults[++count] = entries;
158: }
159: }
160:
161: if (count == -1)
162: return null;
163: int total = 0;
164: for (int i = 0; i <= count; i++)
165: total += allResults[i].length;
166: EntryResult[] allEntries = new EntryResult[total];
167: int next = 0;
168: for (int i = 0; i <= count; i++) {
169: EntryResult[] entries = allResults[i];
170: System.arraycopy(entries, 0, allEntries, next,
171: entries.length);
172: next += entries.length;
173: }
174: return allEntries;
175: }
176:
177: protected StringBuffer print(StringBuffer output) {
178: switch (this .typeSuffix) {
179: case CLASS_SUFFIX:
180: output.append("MultiClassDeclarationPattern: "); //$NON-NLS-1$
181: break;
182: case CLASS_AND_INTERFACE_SUFFIX:
183: output.append("MultiClassAndInterfaceDeclarationPattern: "); //$NON-NLS-1$
184: break;
185: case CLASS_AND_ENUM_SUFFIX:
186: output.append("MultiClassAndEnumDeclarationPattern: "); //$NON-NLS-1$
187: break;
188: case INTERFACE_SUFFIX:
189: output.append("MultiInterfaceDeclarationPattern: "); //$NON-NLS-1$
190: break;
191: case INTERFACE_AND_ANNOTATION_SUFFIX:
192: output
193: .append("MultiInterfaceAndAnnotationDeclarationPattern: "); //$NON-NLS-1$
194: break;
195: case ENUM_SUFFIX:
196: output.append("MultiEnumDeclarationPattern: "); //$NON-NLS-1$
197: break;
198: case ANNOTATION_TYPE_SUFFIX:
199: output.append("MultiAnnotationTypeDeclarationPattern: "); //$NON-NLS-1$
200: break;
201: default:
202: output.append("MultiTypeDeclarationPattern: "); //$NON-NLS-1$
203: break;
204: }
205: if (qualifications != null) {
206: output.append("qualifications: <"); //$NON-NLS-1$
207: for (int i = 0; i < qualifications.length; i++) {
208: output.append(qualifications[i]);
209: if (i < qualifications.length - 1)
210: output.append(", "); //$NON-NLS-1$
211: }
212: output.append("> "); //$NON-NLS-1$
213: }
214: if (simpleNames != null) {
215: output.append("simpleNames: <"); //$NON-NLS-1$
216: for (int i = 0; i < simpleNames.length; i++) {
217: output.append(simpleNames[i]);
218: if (i < simpleNames.length - 1)
219: output.append(", "); //$NON-NLS-1$
220: }
221: output.append(">"); //$NON-NLS-1$
222: }
223: return super.print(output);
224: }
225: }
|