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.*;
015: import org.eclipse.jdt.core.compiler.CharOperation;
016: import org.eclipse.jdt.core.search.SearchPattern;
017: import org.eclipse.jdt.internal.core.index.*;
018: import org.eclipse.jdt.internal.core.util.Util;
019:
020: public class MethodPattern extends JavaSearchPattern {
021:
022: protected boolean findDeclarations;
023: protected boolean findReferences;
024:
025: public char[] selector;
026:
027: public char[] declaringQualification;
028: public char[] declaringSimpleName;
029:
030: public char[] returnQualification;
031: public char[] returnSimpleName;
032:
033: public char[][] parameterQualifications;
034: public char[][] parameterSimpleNames;
035: public int parameterCount;
036: public boolean varargs = false;
037:
038: // extra reference info
039: protected IType declaringType;
040:
041: // Signatures and arguments for generic search
042: char[][] returnTypeSignatures;
043: char[][][] returnTypeArguments;
044: char[][][] parametersTypeSignatures;
045: char[][][][] parametersTypeArguments;
046: boolean methodParameters = false;
047: char[][] methodArguments;
048:
049: protected static char[][] REF_CATEGORIES = { METHOD_REF };
050: protected static char[][] REF_AND_DECL_CATEGORIES = { METHOD_REF,
051: METHOD_DECL };
052: protected static char[][] DECL_CATEGORIES = { METHOD_DECL };
053:
054: /**
055: * Method entries are encoded as selector '/' Arity:
056: * e.g. 'foo/0'
057: */
058: public static char[] createIndexKey(char[] selector, int argCount) {
059: char[] countChars = argCount < 10 ? COUNTS[argCount]
060: : ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
061: return CharOperation.concat(selector, countChars);
062: }
063:
064: MethodPattern(int matchRule) {
065: super (METHOD_PATTERN, matchRule);
066: }
067:
068: public MethodPattern(boolean findDeclarations,
069: boolean findReferences, char[] selector,
070: char[] declaringQualification, char[] declaringSimpleName,
071: char[] returnQualification, char[] returnSimpleName,
072: char[][] parameterQualifications,
073: char[][] parameterSimpleNames, IType declaringType,
074: int matchRule) {
075:
076: this (matchRule);
077:
078: this .findDeclarations = findDeclarations;
079: this .findReferences = findReferences;
080:
081: this .selector = (this .isCaseSensitive || this .isCamelCase) ? selector
082: : CharOperation.toLowerCase(selector);
083: this .declaringQualification = this .isCaseSensitive ? declaringQualification
084: : CharOperation.toLowerCase(declaringQualification);
085: this .declaringSimpleName = this .isCaseSensitive ? declaringSimpleName
086: : CharOperation.toLowerCase(declaringSimpleName);
087: this .returnQualification = this .isCaseSensitive ? returnQualification
088: : CharOperation.toLowerCase(returnQualification);
089: this .returnSimpleName = this .isCaseSensitive ? returnSimpleName
090: : CharOperation.toLowerCase(returnSimpleName);
091: if (parameterSimpleNames != null) {
092: this .parameterCount = parameterSimpleNames.length;
093: this .parameterQualifications = new char[this .parameterCount][];
094: this .parameterSimpleNames = new char[this .parameterCount][];
095: for (int i = 0; i < this .parameterCount; i++) {
096: this .parameterQualifications[i] = this .isCaseSensitive ? parameterQualifications[i]
097: : CharOperation
098: .toLowerCase(parameterQualifications[i]);
099: this .parameterSimpleNames[i] = this .isCaseSensitive ? parameterSimpleNames[i]
100: : CharOperation
101: .toLowerCase(parameterSimpleNames[i]);
102: }
103: } else {
104: this .parameterCount = -1;
105: }
106: this .declaringType = declaringType;
107: ((InternalSearchPattern) this ).mustResolve = mustResolve();
108: }
109:
110: /*
111: * Instanciate a method pattern with signatures for generics search
112: */
113: public MethodPattern(boolean findDeclarations,
114: boolean findReferences, char[] selector,
115: char[] declaringQualification, char[] declaringSimpleName,
116: char[] returnQualification, char[] returnSimpleName,
117: String returnSignature, char[][] parameterQualifications,
118: char[][] parameterSimpleNames,
119: String[] parameterSignatures, IMethod method, int matchRule) {
120:
121: this (findDeclarations, findReferences, selector,
122: declaringQualification, declaringSimpleName,
123: returnQualification, returnSimpleName,
124: parameterQualifications, parameterSimpleNames, method
125: .getDeclaringType(), 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 genericSignature = null;
137: String key;
138: if (method.isResolved()
139: && (new BindingKey(key = method.getKey()))
140: .isParameterizedType()) {
141: genericDeclaringTypeSignature = Util
142: .getDeclaringTypeSignature(key);
143: } else {
144: methodParameters = true;
145: }
146:
147: // Store type signature and arguments for declaring type
148: if (genericDeclaringTypeSignature != null) {
149: this .typeSignatures = Util
150: .splitTypeLevelsSignature(genericDeclaringTypeSignature);
151: setTypeArguments(Util
152: .getAllTypeArguments(this .typeSignatures));
153: } else {
154: storeTypeSignaturesAndArguments(declaringType);
155: }
156:
157: // Store type signatures and arguments for return type
158: if (returnSignature != null) {
159: returnTypeSignatures = Util
160: .splitTypeLevelsSignature(returnSignature);
161: returnTypeArguments = Util
162: .getAllTypeArguments(returnTypeSignatures);
163: }
164:
165: // Store type signatures and arguments for method parameters type
166: if (parameterSignatures != null) {
167: int length = parameterSignatures.length;
168: if (length > 0) {
169: parametersTypeSignatures = new char[length][][];
170: parametersTypeArguments = new char[length][][][];
171: for (int i = 0; i < length; i++) {
172: parametersTypeSignatures[i] = Util
173: .splitTypeLevelsSignature(parameterSignatures[i]);
174: parametersTypeArguments[i] = Util
175: .getAllTypeArguments(parametersTypeSignatures[i]);
176: }
177: }
178: }
179:
180: // Store type signatures and arguments for method
181: methodArguments = extractMethodArguments(method);
182: if (hasMethodArguments())
183: ((InternalSearchPattern) this ).mustResolve = true;
184: }
185:
186: /*
187: * Instanciate a method pattern with signatures for generics search
188: */
189: public MethodPattern(boolean findDeclarations,
190: boolean findReferences, char[] selector,
191: char[] declaringQualification, char[] declaringSimpleName,
192: String declaringSignature, char[] returnQualification,
193: char[] returnSimpleName, String returnSignature,
194: char[][] parameterQualifications,
195: char[][] parameterSimpleNames,
196: String[] parameterSignatures, char[][] arguments,
197: int matchRule) {
198:
199: this (findDeclarations, findReferences, selector,
200: declaringQualification, declaringSimpleName,
201: returnQualification, returnSimpleName,
202: parameterQualifications, parameterSimpleNames, null,
203: matchRule);
204:
205: // Store type signature and arguments for declaring type
206: if (declaringSignature != null) {
207: typeSignatures = Util
208: .splitTypeLevelsSignature(declaringSignature);
209: setTypeArguments(Util.getAllTypeArguments(typeSignatures));
210: }
211:
212: // Store type signatures and arguments for return type
213: if (returnSignature != null) {
214: returnTypeSignatures = Util
215: .splitTypeLevelsSignature(returnSignature);
216: returnTypeArguments = Util
217: .getAllTypeArguments(returnTypeSignatures);
218: }
219:
220: // Store type signatures and arguments for method parameters type
221: if (parameterSignatures != null) {
222: int length = parameterSignatures.length;
223: if (length > 0) {
224: parametersTypeSignatures = new char[length][][];
225: parametersTypeArguments = new char[length][][][];
226: for (int i = 0; i < length; i++) {
227: parametersTypeSignatures[i] = Util
228: .splitTypeLevelsSignature(parameterSignatures[i]);
229: parametersTypeArguments[i] = Util
230: .getAllTypeArguments(parametersTypeSignatures[i]);
231: }
232: }
233: }
234:
235: // Store type signatures and arguments for method
236: methodArguments = arguments;
237: if (hasMethodArguments())
238: ((InternalSearchPattern) this ).mustResolve = true;
239: }
240:
241: public void decodeIndexKey(char[] key) {
242: int last = key.length - 1;
243: this .parameterCount = 0;
244: this .selector = null;
245: int power = 1;
246: for (int i = last; i >= 0; i--) {
247: if (key[i] == SEPARATOR) {
248: System.arraycopy(key, 0, this .selector = new char[i],
249: 0, i);
250: break;
251: }
252: if (i == last) {
253: this .parameterCount = key[i] - '0';
254: } else {
255: power *= 10;
256: this .parameterCount += power * (key[i] - '0');
257: }
258: }
259: }
260:
261: public SearchPattern getBlankPattern() {
262: return new MethodPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
263: }
264:
265: public char[][] getIndexCategories() {
266: if (this .findReferences)
267: return this .findDeclarations ? REF_AND_DECL_CATEGORIES
268: : REF_CATEGORIES;
269: if (this .findDeclarations)
270: return DECL_CATEGORIES;
271: return CharOperation.NO_CHAR_CHAR;
272: }
273:
274: boolean hasMethodArguments() {
275: return methodArguments != null && methodArguments.length > 0;
276: }
277:
278: boolean hasMethodParameters() {
279: return methodParameters;
280: }
281:
282: boolean isPolymorphicSearch() {
283: return this .findReferences;
284: }
285:
286: public boolean matchesDecodedKey(SearchPattern decodedPattern) {
287: MethodPattern pattern = (MethodPattern) decodedPattern;
288:
289: return (this .parameterCount == pattern.parameterCount
290: || this .parameterCount == -1 || this .varargs)
291: && matchesName(this .selector, pattern.selector);
292: }
293:
294: /**
295: * Returns whether a method declaration or message send must be resolved to
296: * find out if this method pattern matches it.
297: */
298: protected boolean mustResolve() {
299: // declaring type
300: // If declaring type is specified - even with simple name - always resolves
301: if (declaringSimpleName != null
302: || declaringQualification != null)
303: return true;
304:
305: // return type
306: // If return type is specified - even with simple name - always resolves
307: if (returnSimpleName != null || returnQualification != null)
308: return true;
309:
310: // parameter types
311: if (parameterSimpleNames != null)
312: for (int i = 0, max = parameterSimpleNames.length; i < max; i++)
313: if (parameterQualifications[i] != null)
314: return true;
315: return false;
316: }
317:
318: EntryResult[] queryIn(Index index) throws IOException {
319: char[] key = this .selector; // can be null
320: int matchRule = getMatchRule();
321:
322: switch (getMatchMode()) {
323: case R_EXACT_MATCH:
324: if (this .isCamelCase)
325: break;
326: if (this .selector != null && this .parameterCount >= 0
327: && !this .varargs)
328: key = createIndexKey(this .selector, this .parameterCount);
329: else { // do a prefix query with the selector
330: matchRule &= ~R_EXACT_MATCH;
331: matchRule |= R_PREFIX_MATCH;
332: }
333: break;
334: case R_PREFIX_MATCH:
335: // do a prefix query with the selector
336: break;
337: case R_PATTERN_MATCH:
338: if (this .parameterCount >= 0 && !this .varargs)
339: key = createIndexKey(this .selector == null ? ONE_STAR
340: : this .selector, this .parameterCount);
341: else if (this .selector != null
342: && this .selector[this .selector.length - 1] != '*')
343: key = CharOperation.concat(this .selector, ONE_STAR,
344: SEPARATOR);
345: // else do a pattern query with just the selector
346: break;
347: case R_REGEXP_MATCH:
348: // TODO (frederic) implement regular expression match
349: break;
350: }
351:
352: return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
353: }
354:
355: protected StringBuffer print(StringBuffer output) {
356: if (this .findDeclarations) {
357: output
358: .append(this .findReferences ? "MethodCombinedPattern: " //$NON-NLS-1$
359: : "MethodDeclarationPattern: "); //$NON-NLS-1$
360: } else {
361: output.append("MethodReferencePattern: "); //$NON-NLS-1$
362: }
363: if (declaringQualification != null)
364: output.append(declaringQualification).append('.');
365: if (declaringSimpleName != null)
366: output.append(declaringSimpleName).append('.');
367: else if (declaringQualification != null)
368: output.append("*."); //$NON-NLS-1$
369:
370: if (selector != null)
371: output.append(selector);
372: else
373: output.append("*"); //$NON-NLS-1$
374: output.append('(');
375: if (parameterSimpleNames == null) {
376: output.append("..."); //$NON-NLS-1$
377: } else {
378: for (int i = 0, max = parameterSimpleNames.length; i < max; i++) {
379: if (i > 0)
380: output.append(", "); //$NON-NLS-1$
381: if (parameterQualifications[i] != null)
382: output.append(parameterQualifications[i]).append(
383: '.');
384: if (parameterSimpleNames[i] == null)
385: output.append('*');
386: else
387: output.append(parameterSimpleNames[i]);
388: }
389: }
390: output.append(')');
391: if (returnQualification != null)
392: output
393: .append(" --> ").append(returnQualification).append('.'); //$NON-NLS-1$
394: else if (returnSimpleName != null)
395: output.append(" --> "); //$NON-NLS-1$
396: if (returnSimpleName != null)
397: output.append(returnSimpleName);
398: else if (returnQualification != null)
399: output.append("*"); //$NON-NLS-1$
400: return super.print(output);
401: }
402: }
|