KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > search > matching > ConstructorLocator


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.search.matching;
12
13 import org.eclipse.core.runtime.CoreException;
14 import org.eclipse.jdt.core.IJavaElement;
15 import org.eclipse.jdt.core.compiler.CharOperation;
16 import org.eclipse.jdt.core.search.SearchMatch;
17 import org.eclipse.jdt.core.search.SearchPattern;
18 import org.eclipse.jdt.internal.compiler.ast.*;
19 import org.eclipse.jdt.internal.compiler.lookup.Binding;
20 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
21 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
22 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
23 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
24 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
25
26 public class ConstructorLocator extends PatternLocator {
27
28 protected ConstructorPattern pattern;
29
30 public ConstructorLocator(ConstructorPattern pattern) {
31     super(pattern);
32
33     this.pattern = pattern;
34 }
35 public int match(ASTNode node, MatchingNodeSet nodeSet) { // interested in ExplicitConstructorCall
36
if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
37     if (!(node instanceof ExplicitConstructorCall)) return IMPOSSIBLE_MATCH;
38
39     if (!matchParametersCount(node, ((ExplicitConstructorCall) node).arguments)) return IMPOSSIBLE_MATCH;
40
41     return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
42 }
43 public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) {
44     int referencesLevel = this.pattern.findReferences ? matchLevelForReferences(node) : IMPOSSIBLE_MATCH;
45     int declarationsLevel = this.pattern.findDeclarations ? matchLevelForDeclarations(node) : IMPOSSIBLE_MATCH;
46
47     return nodeSet.addMatch(node, referencesLevel >= declarationsLevel ? referencesLevel : declarationsLevel); // use the stronger match
48
}
49 public int match(Expression node, MatchingNodeSet nodeSet) { // interested in AllocationExpression
50
if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
51     if (!(node instanceof AllocationExpression)) return IMPOSSIBLE_MATCH;
52
53     // constructor name is simple type name
54
AllocationExpression allocation = (AllocationExpression) node;
55     char[][] typeName = allocation.type.getTypeName();
56     if (this.pattern.declaringSimpleName != null && !matchesName(this.pattern.declaringSimpleName, typeName[typeName.length-1]))
57         return IMPOSSIBLE_MATCH;
58
59     if (!matchParametersCount(node, allocation.arguments)) return IMPOSSIBLE_MATCH;
60
61     return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
62 }
63 public int match(FieldDeclaration field, MatchingNodeSet nodeSet) {
64     if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
65     // look only for enum constant
66
if (field.type != null || !(field.initialization instanceof AllocationExpression)) return IMPOSSIBLE_MATCH;
67
68     AllocationExpression allocation = (AllocationExpression) field.initialization;
69     if (field.binding != null && field.binding.declaringClass != null) {
70         if (this.pattern.declaringSimpleName != null && !matchesName(this.pattern.declaringSimpleName, field.binding.declaringClass.sourceName()))
71             return IMPOSSIBLE_MATCH;
72     }
73
74     if (!matchParametersCount(field, allocation.arguments)) return IMPOSSIBLE_MATCH;
75
76     return nodeSet.addMatch(field, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
77 }
78 //public int match(MethodDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
79
/**
80  * Special case for message send in javadoc comment. They can be in fact bound to a contructor.
81  * @see "http://bugs.eclipse.org/bugs/show_bug.cgi?id=83285"
82  */

83 public int match(MessageSend msgSend, MatchingNodeSet nodeSet) {
84     if ((msgSend.bits & ASTNode.InsideJavadoc) == 0) return IMPOSSIBLE_MATCH;
85     if (this.pattern.declaringSimpleName == null || CharOperation.equals(msgSend.selector, this.pattern.declaringSimpleName)) {
86         return nodeSet.addMatch(msgSend, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
87     }
88     return IMPOSSIBLE_MATCH;
89 }
90 //public int match(Reference node, MatchingNodeSet nodeSet) - SKIP IT
91
public int match(TypeDeclaration node, MatchingNodeSet nodeSet) {
92     if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
93
94     // need to look for a generated default constructor
95
return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
96 }
97 //public int match(TypeReference node, MatchingNodeSet nodeSet) - SKIP IT
98

99 protected int matchConstructor(MethodBinding constructor) {
100     if (!constructor.isConstructor()) return IMPOSSIBLE_MATCH;
101
102     // declaring type, simple name has already been matched by matchIndexEntry()
103
int level = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, constructor.declaringClass);
104     if (level == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
105
106     // parameter types
107
int parameterCount = this.pattern.parameterCount;
108     if (parameterCount > -1) {
109         if (constructor.parameters == null) return INACCURATE_MATCH;
110         if (parameterCount != constructor.parameters.length) return IMPOSSIBLE_MATCH;
111         for (int i = 0; i < parameterCount; i++) {
112             // TODO (frederic) use this call to refine accuracy on parameter types
113
// int newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0, constructor.parameters[i]);
114
int newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], constructor.parameters[i]);
115             if (level > newLevel) {
116                 if (newLevel == IMPOSSIBLE_MATCH) {
117 // if (isErasureMatch) {
118
// return ERASURE_MATCH;
119
// }
120
return IMPOSSIBLE_MATCH;
121                 }
122                 level = newLevel; // can only be downgraded
123
}
124         }
125     }
126     return level;
127 }
128 protected int matchContainer() {
129     if (this.pattern.findReferences) return ALL_CONTAINER; // handles both declarations + references & just references
130
// COMPILATION_UNIT_CONTAINER - implicit constructor call: case of Y extends X and Y doesn't define any constructor
131
// CLASS_CONTAINER - implicit constructor call: case of constructor declaration with no explicit super call
132
// METHOD_CONTAINER - reference in another constructor
133
// FIELD_CONTAINER - anonymous in a field initializer
134

135     // declarations are only found in Class
136
return CLASS_CONTAINER;
137 }
138 protected int matchLevelForReferences(ConstructorDeclaration constructor) {
139     ExplicitConstructorCall constructorCall = constructor.constructorCall;
140     if (constructorCall == null || constructorCall.accessMode != ExplicitConstructorCall.ImplicitSuper)
141         return IMPOSSIBLE_MATCH;
142
143     if (this.pattern.parameterSimpleNames != null) {
144         int length = this.pattern.parameterSimpleNames.length;
145         Expression[] args = constructorCall.arguments;
146         int argsLength = args == null ? 0 : args.length;
147         if (length != argsLength) return IMPOSSIBLE_MATCH;
148     }
149     return ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
150 }
151 protected int matchLevelForDeclarations(ConstructorDeclaration constructor) {
152     // constructor name is stored in selector field
153
if (this.pattern.declaringSimpleName != null && !matchesName(this.pattern.declaringSimpleName, constructor.selector))
154         return IMPOSSIBLE_MATCH;
155
156     if (this.pattern.parameterSimpleNames != null) {
157         int length = this.pattern.parameterSimpleNames.length;
158         Argument[] args = constructor.arguments;
159         int argsLength = args == null ? 0 : args.length;
160         if (length != argsLength) return IMPOSSIBLE_MATCH;
161     }
162
163     // Verify type arguments (do not reject if pattern has no argument as it can be an erasure match)
164
if (this.pattern.hasConstructorArguments()) {
165         if (constructor.typeParameters == null || constructor.typeParameters.length != this.pattern.constructorArguments.length) return IMPOSSIBLE_MATCH;
166     }
167
168     return ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
169 }
170 boolean matchParametersCount(ASTNode node, Expression[] args) {
171     if (this.pattern.parameterSimpleNames != null && (!this.pattern.varargs || ((node.bits & ASTNode.InsideJavadoc) != 0))) {
172         int length = this.pattern.parameterCount;
173         if (length < 0) length = this.pattern.parameterSimpleNames.length;
174         int argsLength = args == null ? 0 : args.length;
175         if (length != argsLength) {
176             return false;
177         }
178     }
179     return true;
180 }
181 protected void matchReportReference(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException {
182
183     MethodBinding constructorBinding = null;
184     boolean isSynthetic = false;
185     if (reference instanceof ExplicitConstructorCall) {
186         ExplicitConstructorCall call = (ExplicitConstructorCall) reference;
187         isSynthetic = call.isImplicitSuper();
188         constructorBinding = call.binding;
189     } else if (reference instanceof AllocationExpression) {
190         AllocationExpression alloc = (AllocationExpression) reference;
191         constructorBinding = alloc.binding;
192     } else if (reference instanceof TypeDeclaration || reference instanceof FieldDeclaration) {
193         super.matchReportReference(reference, element, elementBinding, accuracy, locator);
194         if (match != null) return;
195     }
196
197     // Create search match
198
match = locator.newMethodReferenceMatch(element, elementBinding, accuracy, -1, -1, true, isSynthetic, reference);
199
200     // Look to refine accuracy
201
if (constructorBinding instanceof ParameterizedGenericMethodBinding) { // parameterized generic method
202
// Update match regarding constructor type arguments
203
ParameterizedGenericMethodBinding parameterizedMethodBinding = (ParameterizedGenericMethodBinding) constructorBinding;
204         match.setRaw(parameterizedMethodBinding.isRaw);
205         TypeBinding[] typeBindings = parameterizedMethodBinding.isRaw ? null : parameterizedMethodBinding.typeArguments;
206         updateMatch(typeBindings, locator, this.pattern.constructorArguments, this.pattern.hasConstructorParameters());
207
208         // Update match regarding declaring class type arguments
209
if (constructorBinding.declaringClass.isParameterizedType() || constructorBinding.declaringClass.isRawType()) {
210             ParameterizedTypeBinding parameterizedBinding = (ParameterizedTypeBinding)constructorBinding.declaringClass;
211             if (!this.pattern.hasTypeArguments() && this.pattern.hasConstructorArguments() || parameterizedBinding.isParameterizedWithOwnVariables()) {
212                 // special case for constructor pattern which defines arguments but no type
213
// in this case, we only use refined accuracy for constructor
214
} else if (this.pattern.hasTypeArguments() && !this.pattern.hasConstructorArguments()) {
215                 // special case for constructor pattern which defines no constructor arguments but has type ones
216
// in this case, we do not use refined accuracy
217
updateMatch(parameterizedBinding, this.pattern.getTypeArguments(), this.pattern.hasTypeParameters(), 0, locator);
218             } else {
219                 updateMatch(parameterizedBinding, this.pattern.getTypeArguments(), this.pattern.hasTypeParameters(), 0, locator);
220             }
221         } else if (this.pattern.hasTypeArguments()) {
222             match.setRule(SearchPattern.R_ERASURE_MATCH);
223         }
224
225         // Update match regarding constructor parameters
226
// TODO ? (frederic)
227
} else if (constructorBinding instanceof ParameterizedMethodBinding) {
228         // Update match regarding declaring class type arguments
229
if (constructorBinding.declaringClass.isParameterizedType() || constructorBinding.declaringClass.isRawType()) {
230             ParameterizedTypeBinding parameterizedBinding = (ParameterizedTypeBinding)constructorBinding.declaringClass;
231             if (!this.pattern.hasTypeArguments() && this.pattern.hasConstructorArguments()) {
232                 // special case for constructor pattern which defines arguments but no type
233
updateMatch(parameterizedBinding, new char[][][] {this.pattern.constructorArguments}, this.pattern.hasTypeParameters(), 0, locator);
234             } else if (!parameterizedBinding.isParameterizedWithOwnVariables()) {
235                 updateMatch(parameterizedBinding, this.pattern.getTypeArguments(), this.pattern.hasTypeParameters(), 0, locator);
236             }
237         } else if (this.pattern.hasTypeArguments()) {
238             match.setRule(SearchPattern.R_ERASURE_MATCH);
239         }
240
241         // Update match regarding constructor parameters
242
// TODO ? (frederic)
243
} else if (this.pattern.hasConstructorArguments()) { // binding has no type params, compatible erasure if pattern does
244
match.setRule(SearchPattern.R_ERASURE_MATCH);
245     }
246
247     // See whether it is necessary to report or not
248
if (match.getRule() == 0) return; // impossible match
249
boolean report = (this.isErasureMatch && match.isErasure()) || (this.isEquivalentMatch && match.isEquivalent()) || match.isExact();
250     if (!report) return;
251
252     // Report match
253
int offset = reference.sourceStart;
254     match.setOffset(offset);
255     match.setLength(reference.sourceEnd - offset + 1);
256     if (reference instanceof FieldDeclaration) { // enum declaration
257
FieldDeclaration enumConstant = (FieldDeclaration) reference;
258         if (enumConstant.initialization instanceof QualifiedAllocationExpression) {
259             locator.reportAccurateEnumConstructorReference(match, enumConstant, (QualifiedAllocationExpression) enumConstant.initialization);
260             return;
261         }
262     }
263     locator.report(match);
264 }
265 public SearchMatch newDeclarationMatch(ASTNode reference, IJavaElement element, Binding binding, int accuracy, int length, MatchLocator locator) {
266     match = null;
267     int offset = reference.sourceStart;
268     if (this.pattern.findReferences) {
269         if (reference instanceof TypeDeclaration) {
270             TypeDeclaration type = (TypeDeclaration) reference;
271             AbstractMethodDeclaration[] methods = type.methods;
272             if (methods != null) {
273                 for (int i = 0, max = methods.length; i < max; i++) {
274                     AbstractMethodDeclaration method = methods[i];
275                     boolean synthetic = method.isDefaultConstructor() && method.sourceStart < type.bodyStart;
276                     match = locator.newMethodReferenceMatch(element, binding, accuracy, offset, length, method.isConstructor(), synthetic, method);
277                 }
278             }
279         } else if (reference instanceof ConstructorDeclaration) {
280             ConstructorDeclaration constructor = (ConstructorDeclaration) reference;
281             ExplicitConstructorCall call = constructor.constructorCall;
282             boolean synthetic = call != null && call.isImplicitSuper();
283             match = locator.newMethodReferenceMatch(element, binding, accuracy, offset, length, constructor.isConstructor(), synthetic, constructor);
284         }
285     }
286     if (match != null) {
287         return match;
288     }
289     // super implementation...
290
return locator.newDeclarationMatch(element, binding, accuracy, reference.sourceStart, length);
291 }
292 public int resolveLevel(ASTNode node) {
293     if (this.pattern.findReferences) {
294         if (node instanceof AllocationExpression)
295             return resolveLevel((AllocationExpression) node);
296         if (node instanceof ExplicitConstructorCall)
297             return resolveLevel(((ExplicitConstructorCall) node).binding);
298         if (node instanceof TypeDeclaration)
299             return resolveLevel((TypeDeclaration) node);
300         if (node instanceof FieldDeclaration)
301             return resolveLevel((FieldDeclaration) node);
302         if (node instanceof JavadocMessageSend) {
303             return resolveLevel(((JavadocMessageSend)node).binding);
304         }
305     }
306     if (node instanceof ConstructorDeclaration)
307         return resolveLevel((ConstructorDeclaration) node, true);
308     return IMPOSSIBLE_MATCH;
309 }
310 protected int referenceType() {
311     return IJavaElement.METHOD;
312 }
313 protected int resolveLevel(AllocationExpression allocation) {
314     // constructor name is simple type name
315
char[][] typeName = allocation.type.getTypeName();
316     if (this.pattern.declaringSimpleName != null && !matchesName(this.pattern.declaringSimpleName, typeName[typeName.length-1]))
317         return IMPOSSIBLE_MATCH;
318
319     return resolveLevel(allocation.binding);
320 }
321 protected int resolveLevel(FieldDeclaration field) {
322     // only accept enum constants
323
if (field.type != null || field.binding == null) return IMPOSSIBLE_MATCH;
324     if (this.pattern.declaringSimpleName != null && !matchesName(this.pattern.declaringSimpleName, field.binding.type.sourceName()))
325         return IMPOSSIBLE_MATCH;
326     if (!(field.initialization instanceof AllocationExpression) || field.initialization.resolvedType.isLocalType()) return IMPOSSIBLE_MATCH;
327
328     return resolveLevel(((AllocationExpression)field.initialization).binding);
329 }
330 public int resolveLevel(Binding binding) {
331     if (binding == null) return INACCURATE_MATCH;
332     if (!(binding instanceof MethodBinding)) return IMPOSSIBLE_MATCH;
333
334     MethodBinding constructor = (MethodBinding) binding;
335     int level= matchConstructor(constructor);
336     if (level== IMPOSSIBLE_MATCH) {
337         if (constructor != constructor.original()) {
338             level= matchConstructor(constructor.original());
339         }
340     }
341     return level;
342 }
343 protected int resolveLevel(ConstructorDeclaration constructor, boolean checkDeclarations) {
344     int referencesLevel = IMPOSSIBLE_MATCH;
345     if (this.pattern.findReferences) {
346         ExplicitConstructorCall constructorCall = constructor.constructorCall;
347         if (constructorCall != null && constructorCall.accessMode == ExplicitConstructorCall.ImplicitSuper) {
348             // eliminate explicit super call as it will be treated with matchLevel(ExplicitConstructorCall, boolean)
349
int callCount = (constructorCall.arguments == null) ? 0 : constructorCall.arguments.length;
350             int patternCount = (this.pattern.parameterSimpleNames == null) ? 0 : this.pattern.parameterSimpleNames.length;
351             if (patternCount != callCount) {
352                 referencesLevel = IMPOSSIBLE_MATCH;
353             } else {
354                 referencesLevel = resolveLevel(constructorCall.binding);
355                 if (referencesLevel == ACCURATE_MATCH) return ACCURATE_MATCH; // cannot get better
356
}
357         }
358     }
359     if (!checkDeclarations) return referencesLevel;
360
361     int declarationsLevel = this.pattern.findDeclarations ? resolveLevel(constructor.binding) : IMPOSSIBLE_MATCH;
362     return referencesLevel >= declarationsLevel ? referencesLevel : declarationsLevel; // answer the stronger match
363
}
364 protected int resolveLevel(TypeDeclaration type) {
365     // find default constructor
366
AbstractMethodDeclaration[] methods = type.methods;
367     if (methods != null) {
368         for (int i = 0, length = methods.length; i < length; i++) {
369             AbstractMethodDeclaration method = methods[i];
370             if (method.isDefaultConstructor() && method.sourceStart < type.bodyStart) // if synthetic
371
return resolveLevel((ConstructorDeclaration) method, false);
372         }
373     }
374     return IMPOSSIBLE_MATCH;
375 }
376 public String JavaDoc toString() {
377     return "Locator for " + this.pattern.toString(); //$NON-NLS-1$
378
}
379 }
380
Popular Tags