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.BindingKey;
015: import org.eclipse.jdt.core.Flags;
016: import org.eclipse.jdt.core.IMethod;
017: import org.eclipse.jdt.core.JavaModelException;
018: import org.eclipse.jdt.core.compiler.CharOperation;
019: import org.eclipse.jdt.core.search.SearchPattern;
020: import org.eclipse.jdt.internal.core.index.EntryResult;
021: import org.eclipse.jdt.internal.core.index.Index;
022: import org.eclipse.jdt.internal.core.util.Util;
023:
024: public class ConstructorPattern extends JavaSearchPattern {
025:
026: protected boolean findDeclarations;
027: protected boolean findReferences;
028:
029: public char[] declaringQualification;
030: public char[] declaringSimpleName;
031:
032: public char[][] parameterQualifications;
033: public char[][] parameterSimpleNames;
034: public int parameterCount;
035: public boolean varargs = false;
036:
037: // Signatures and arguments for generic search
038: char[][][] parametersTypeSignatures;
039: char[][][][] parametersTypeArguments;
040: boolean constructorParameters = false;
041: char[][] constructorArguments;
042:
043: protected static char[][] REF_CATEGORIES = { CONSTRUCTOR_REF };
044: protected static char[][] REF_AND_DECL_CATEGORIES = {
045: CONSTRUCTOR_REF, CONSTRUCTOR_DECL };
046: protected static char[][] DECL_CATEGORIES = { CONSTRUCTOR_DECL };
047:
048: /**
049: * Constructor entries are encoded as TypeName '/' Arity:
050: * e.g. 'X/0'
051: */
052: public static char[] createIndexKey(char[] typeName, int argCount) {
053: char[] countChars = argCount < 10 ? COUNTS[argCount]
054: : ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
055: return CharOperation.concat(typeName, countChars);
056: }
057:
058: ConstructorPattern(int matchRule) {
059: super (CONSTRUCTOR_PATTERN, matchRule);
060: }
061:
062: public ConstructorPattern(boolean findDeclarations,
063: boolean findReferences, char[] declaringSimpleName,
064: char[] declaringQualification,
065: char[][] parameterQualifications,
066: char[][] parameterSimpleNames, int matchRule) {
067:
068: this (matchRule);
069:
070: this .findDeclarations = findDeclarations;
071: this .findReferences = findReferences;
072:
073: this .declaringQualification = this .isCaseSensitive ? declaringQualification
074: : CharOperation.toLowerCase(declaringQualification);
075: this .declaringSimpleName = (this .isCaseSensitive || this .isCamelCase) ? declaringSimpleName
076: : CharOperation.toLowerCase(declaringSimpleName);
077: if (parameterSimpleNames != null) {
078: this .parameterCount = parameterSimpleNames.length;
079: boolean synthetic = this .parameterCount > 0
080: && declaringQualification != null
081: && CharOperation.equals(CharOperation.concat(
082: parameterQualifications[0],
083: parameterSimpleNames[0], '.'),
084: declaringQualification);
085: int offset = 0;
086: if (synthetic) {
087: // skip first synthetic parameter
088: this .parameterCount--;
089: offset++;
090: }
091: this .parameterQualifications = new char[this .parameterCount][];
092: this .parameterSimpleNames = new char[this .parameterCount][];
093: for (int i = 0; i < this .parameterCount; i++) {
094: this .parameterQualifications[i] = this .isCaseSensitive ? parameterQualifications[i
095: + offset]
096: : CharOperation
097: .toLowerCase(parameterQualifications[i
098: + offset]);
099: this .parameterSimpleNames[i] = this .isCaseSensitive ? parameterSimpleNames[i
100: + offset]
101: : CharOperation
102: .toLowerCase(parameterSimpleNames[i
103: + offset]);
104: }
105: } else {
106: this .parameterCount = -1;
107: }
108: ((InternalSearchPattern) this ).mustResolve = mustResolve();
109: }
110:
111: /*
112: * Instanciate a method pattern with signatures for generics search
113: */
114: public ConstructorPattern(boolean findDeclarations,
115: boolean findReferences, char[] declaringSimpleName,
116: char[] declaringQualification,
117: char[][] parameterQualifications,
118: char[][] parameterSimpleNames,
119: String[] parameterSignatures, IMethod method,
120: // boolean varargs,
121: int matchRule) {
122:
123: this (findDeclarations, findReferences, declaringSimpleName,
124: declaringQualification, parameterQualifications,
125: parameterSimpleNames, matchRule);
126:
127: // Set flags
128: try {
129: this .varargs = (method.getFlags() & Flags.AccVarargs) != 0;
130: } catch (JavaModelException e) {
131: // do nothing
132: }
133:
134: // Get unique key for parameterized constructors
135: String genericDeclaringTypeSignature = null;
136: String key;
137: if (method.isResolved()
138: && new BindingKey(key = method.getKey())
139: .isParameterizedType()) {
140: genericDeclaringTypeSignature = Util
141: .getDeclaringTypeSignature(key);
142: } else {
143: constructorParameters = true;
144: }
145:
146: // Store type signature and arguments for declaring type
147: if (genericDeclaringTypeSignature != null) {
148: this .typeSignatures = Util
149: .splitTypeLevelsSignature(genericDeclaringTypeSignature);
150: setTypeArguments(Util
151: .getAllTypeArguments(this .typeSignatures));
152: } else {
153: storeTypeSignaturesAndArguments(method.getDeclaringType());
154: }
155:
156: // store type signatures and arguments for method parameters type
157: if (parameterSignatures != null) {
158: int length = parameterSignatures.length;
159: if (length > 0) {
160: parametersTypeSignatures = new char[length][][];
161: parametersTypeArguments = new char[length][][][];
162: for (int i = 0; i < length; i++) {
163: parametersTypeSignatures[i] = Util
164: .splitTypeLevelsSignature(parameterSignatures[i]);
165: parametersTypeArguments[i] = Util
166: .getAllTypeArguments(parametersTypeSignatures[i]);
167: }
168: }
169: }
170:
171: // Store type signatures and arguments for method
172: constructorArguments = extractMethodArguments(method);
173: if (hasConstructorArguments())
174: ((InternalSearchPattern) this ).mustResolve = true;
175: }
176:
177: /*
178: * Instanciate a method pattern with signatures for generics search
179: */
180: public ConstructorPattern(boolean findDeclarations,
181: boolean findReferences, char[] declaringSimpleName,
182: char[] declaringQualification, String declaringSignature,
183: char[][] parameterQualifications,
184: char[][] parameterSimpleNames,
185: String[] parameterSignatures, char[][] arguments,
186: int matchRule) {
187:
188: this (findDeclarations, findReferences, declaringSimpleName,
189: declaringQualification, parameterQualifications,
190: parameterSimpleNames, matchRule);
191:
192: // Store type signature and arguments for declaring type
193: if (declaringSignature != null) {
194: typeSignatures = Util
195: .splitTypeLevelsSignature(declaringSignature);
196: setTypeArguments(Util.getAllTypeArguments(typeSignatures));
197: }
198:
199: // Store type signatures and arguments for method parameters type
200: if (parameterSignatures != null) {
201: int length = parameterSignatures.length;
202: if (length > 0) {
203: parametersTypeSignatures = new char[length][][];
204: parametersTypeArguments = new char[length][][][];
205: for (int i = 0; i < length; i++) {
206: parametersTypeSignatures[i] = Util
207: .splitTypeLevelsSignature(parameterSignatures[i]);
208: parametersTypeArguments[i] = Util
209: .getAllTypeArguments(parametersTypeSignatures[i]);
210: }
211: }
212: }
213:
214: // Store type signatures and arguments for method
215: constructorArguments = arguments;
216: if (arguments == null || arguments.length == 0) {
217: if (getTypeArguments() != null
218: && getTypeArguments().length > 0) {
219: constructorArguments = getTypeArguments()[0];
220: }
221: }
222: if (hasConstructorArguments())
223: ((InternalSearchPattern) this ).mustResolve = true;
224: }
225:
226: public void decodeIndexKey(char[] key) {
227: int last = key.length - 1;
228: this .parameterCount = 0;
229: this .declaringSimpleName = null;
230: int power = 1;
231: for (int i = last; i >= 0; i--) {
232: if (key[i] == SEPARATOR) {
233: System.arraycopy(key, 0,
234: this .declaringSimpleName = new char[i], 0, i);
235: break;
236: }
237: if (i == last) {
238: this .parameterCount = key[i] - '0';
239: } else {
240: power *= 10;
241: this .parameterCount += power * (key[i] - '0');
242: }
243: }
244: }
245:
246: public SearchPattern getBlankPattern() {
247: return new ConstructorPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
248: }
249:
250: public char[][] getIndexCategories() {
251: if (this .findReferences)
252: return this .findDeclarations ? REF_AND_DECL_CATEGORIES
253: : REF_CATEGORIES;
254: if (this .findDeclarations)
255: return DECL_CATEGORIES;
256: return CharOperation.NO_CHAR_CHAR;
257: }
258:
259: boolean hasConstructorArguments() {
260: return constructorArguments != null
261: && constructorArguments.length > 0;
262: }
263:
264: boolean hasConstructorParameters() {
265: return constructorParameters;
266: }
267:
268: public boolean matchesDecodedKey(SearchPattern decodedPattern) {
269: ConstructorPattern pattern = (ConstructorPattern) decodedPattern;
270:
271: return (this .parameterCount == pattern.parameterCount
272: || this .parameterCount == -1 || this .varargs)
273: && matchesName(this .declaringSimpleName,
274: pattern.declaringSimpleName);
275: }
276:
277: protected boolean mustResolve() {
278: if (this .declaringQualification != null)
279: return true;
280:
281: // parameter types
282: if (this .parameterSimpleNames != null)
283: for (int i = 0, max = this .parameterSimpleNames.length; i < max; i++)
284: if (this .parameterQualifications[i] != null)
285: return true;
286: return this .findReferences; // need to check resolved default constructors and explicit constructor calls
287: }
288:
289: EntryResult[] queryIn(Index index) throws IOException {
290: char[] key = this .declaringSimpleName; // can be null
291: int matchRule = getMatchRule();
292:
293: switch (getMatchMode()) {
294: case R_EXACT_MATCH:
295: if (this .isCamelCase)
296: break;
297: if (this .declaringSimpleName != null
298: && this .parameterCount >= 0 && !this .varargs)
299: key = createIndexKey(this .declaringSimpleName,
300: this .parameterCount);
301: else { // do a prefix query with the declaringSimpleName
302: matchRule &= ~R_EXACT_MATCH;
303: matchRule |= R_PREFIX_MATCH;
304: }
305: break;
306: case R_PREFIX_MATCH:
307: // do a prefix query with the declaringSimpleName
308: break;
309: case R_PATTERN_MATCH:
310: if (this .parameterCount >= 0 && !this .varargs)
311: key = createIndexKey(
312: this .declaringSimpleName == null ? ONE_STAR
313: : this .declaringSimpleName,
314: this .parameterCount);
315: else if (this .declaringSimpleName != null
316: && this .declaringSimpleName[this .declaringSimpleName.length - 1] != '*')
317: key = CharOperation.concat(this .declaringSimpleName,
318: ONE_STAR, SEPARATOR);
319: // else do a pattern query with just the declaringSimpleName
320: break;
321: case R_REGEXP_MATCH:
322: // TODO (frederic) implement regular expression match
323: break;
324: }
325:
326: return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
327: }
328:
329: protected StringBuffer print(StringBuffer output) {
330: if (this .findDeclarations) {
331: output
332: .append(this .findReferences ? "ConstructorCombinedPattern: " //$NON-NLS-1$
333: : "ConstructorDeclarationPattern: "); //$NON-NLS-1$
334: } else {
335: output.append("ConstructorReferencePattern: "); //$NON-NLS-1$
336: }
337: if (declaringQualification != null)
338: output.append(declaringQualification).append('.');
339: if (declaringSimpleName != null)
340: output.append(declaringSimpleName);
341: else if (declaringQualification != null)
342: output.append("*"); //$NON-NLS-1$
343:
344: output.append('(');
345: if (parameterSimpleNames == null) {
346: output.append("..."); //$NON-NLS-1$
347: } else {
348: for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
349: if (i > 0)
350: output.append(", "); //$NON-NLS-1$
351: if (parameterQualifications[i] != null)
352: output.append(parameterQualifications[i]).append(
353: '.');
354: if (parameterSimpleNames[i] == null)
355: output.append('*');
356: else
357: output.append(parameterSimpleNames[i]);
358: }
359: }
360: output.append(')');
361: return super.print(output);
362: }
363: }
|