KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > lookup > MethodVerifier15


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.compiler.lookup;
12
13 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
14 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
15 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
16
17 class MethodVerifier15 extends MethodVerifier {
18
19 MethodVerifier15(LookupEnvironment environment) {
20     super(environment);
21 }
22 boolean areMethodsCompatible(MethodBinding one, MethodBinding two) {
23     MethodBinding sub = computeSubstituteMethod(two, one);
24     return sub != null && doesSubstituteMethodOverride(one, sub) && areReturnTypesCompatible(one, sub);
25 }
26 boolean areParametersEqual(MethodBinding one, MethodBinding two) {
27     TypeBinding[] oneArgs = one.parameters;
28     TypeBinding[] twoArgs = two.parameters;
29     if (oneArgs == twoArgs) return true;
30
31     int length = oneArgs.length;
32     if (length != twoArgs.length) return false;
33
34     if (one.declaringClass.isInterface()) {
35         for (int i = 0; i < length; i++)
36             if (!areTypesEqual(oneArgs[i], twoArgs[i]))
37                 return false;
38     } else {
39         // methods with raw parameters are considered equal to inherited methods
40
// with parameterized parameters for backwards compatibility, need a more complex check
41
int i;
42         foundRAW: for (i = 0; i < length; i++) {
43             if (!areTypesEqual(oneArgs[i], twoArgs[i])) {
44                 if (oneArgs[i].leafComponentType().isRawType()) {
45                     if (oneArgs[i].dimensions() == twoArgs[i].dimensions() && oneArgs[i].leafComponentType().isEquivalentTo(twoArgs[i].leafComponentType())) {
46                         // one parameter type is raw, hence all parameters types must be raw or non generic
47
// otherwise we have a mismatch check backwards
48
for (int j = 0; j < i; j++)
49                             if (oneArgs[j].leafComponentType().isParameterizedType())
50                                 return false;
51                         // switch to all raw mode
52
break foundRAW;
53                     }
54                 }
55                 return false;
56             }
57         }
58         // all raw mode for remaining parameters (if any)
59
for (i++; i < length; i++) {
60             if (!areTypesEqual(oneArgs[i], twoArgs[i])) {
61                 if (oneArgs[i].leafComponentType().isRawType())
62                     if (oneArgs[i].dimensions() == twoArgs[i].dimensions() && oneArgs[i].leafComponentType().isEquivalentTo(twoArgs[i].leafComponentType()))
63                         continue;
64                 return false;
65             } else if (oneArgs[i].leafComponentType().isParameterizedType()) {
66                 return false; // no remaining parameter can be a Parameterized type (if one has been converted then all RAW types must be converted)
67
}
68         }
69     }
70     return true;
71 }
72 boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two) {
73     if (one.returnType == two.returnType) return true;
74     return areReturnTypesCompatible0(one, two);
75 }
76 boolean areTypesEqual(TypeBinding one, TypeBinding two) {
77     if (one == two) return true;
78
79     // need to consider X<?> and X<? extends Object> as the same 'type'
80
if (one.isParameterizedType() && two.isParameterizedType())
81         return one.isEquivalentTo(two) && two.isEquivalentTo(one);
82
83     // Can skip this since we resolved each method before comparing it, see computeSubstituteMethod()
84
// if (one instanceof UnresolvedReferenceBinding)
85
// return ((UnresolvedReferenceBinding) one).resolvedType == two;
86
// if (two instanceof UnresolvedReferenceBinding)
87
// return ((UnresolvedReferenceBinding) two).resolvedType == one;
88
return false; // all other type bindings are identical
89
}
90 boolean canSkipInheritedMethods() {
91     if (this.type.superclass() != null)
92         if (this.type.superclass().isAbstract() || this.type.superclass().isParameterizedType())
93             return false;
94     return this.type.superInterfaces() == Binding.NO_SUPERINTERFACES;
95 }
96 boolean canSkipInheritedMethods(MethodBinding one, MethodBinding two) {
97     return two == null // already know one is not null
98
|| (one.declaringClass == two.declaringClass && !one.declaringClass.isParameterizedType());
99 }
100 void checkConcreteInheritedMethod(MethodBinding concreteMethod, MethodBinding[] abstractMethods) {
101     super.checkConcreteInheritedMethod(concreteMethod, abstractMethods);
102
103     for (int i = 0, l = abstractMethods.length; i < l; i++) {
104         MethodBinding abstractMethod = abstractMethods[i];
105         if (concreteMethod.isVarargs() != abstractMethod.isVarargs())
106             problemReporter().varargsConflict(concreteMethod, abstractMethod, this.type);
107
108         // so the parameters are equal and the return type is compatible b/w the currentMethod & the substituted inheritedMethod
109
MethodBinding originalInherited = abstractMethod.original();
110         if (originalInherited.returnType != concreteMethod.returnType) {
111             if (abstractMethod.returnType.leafComponentType().isParameterizedType()) {
112                 if (concreteMethod.returnType.leafComponentType().isRawType())
113                     problemReporter().unsafeReturnTypeOverride(concreteMethod, originalInherited, this.type);
114             } else if (abstractMethod.hasSubstitutedReturnType() && originalInherited.returnType.leafComponentType().isTypeVariable()) {
115                 if (((TypeVariableBinding) originalInherited.returnType.leafComponentType()).declaringElement == originalInherited) { // see 81618 - type variable from inherited method
116
TypeBinding currentReturnType = concreteMethod.returnType.leafComponentType();
117                     if (!currentReturnType.isTypeVariable() || ((TypeVariableBinding) currentReturnType).declaringElement != concreteMethod)
118                         problemReporter().unsafeReturnTypeOverride(concreteMethod, originalInherited, this.type);
119                 }
120             }
121         }
122         // check whether bridge method is already defined above for interface methods
123
if (originalInherited.declaringClass.isInterface()
124                 && this.type.superclass.erasure().findSuperTypeWithSameErasure(originalInherited.declaringClass) == null) {
125             this.type.addSyntheticBridgeMethod(originalInherited, concreteMethod.original());
126         }
127     }
128 }
129 void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod, MethodBinding[] allInheritedMethods) {
130     if (currentMethod.isVarargs() != inheritedMethod.isVarargs())
131         problemReporter(currentMethod).varargsConflict(currentMethod, inheritedMethod, this.type);
132
133     // so the parameters are equal and the return type is compatible b/w the currentMethod & the substituted inheritedMethod
134
MethodBinding originalInherited = inheritedMethod.original();
135     if (originalInherited.returnType != currentMethod.returnType) {
136 // if (currentMethod.returnType.needsUncheckedConversion(inheritedMethod.returnType)) {
137
// problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
138
if (inheritedMethod.returnType.leafComponentType().isParameterizedType() && currentMethod.returnType.leafComponentType().isRawType()) {
139             problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
140         } else if (inheritedMethod.hasSubstitutedReturnType() && originalInherited.returnType.leafComponentType().isTypeVariable()) {
141             if (((TypeVariableBinding) originalInherited.returnType.leafComponentType()).declaringElement == originalInherited) { // see 81618 - type variable from inherited method
142
TypeBinding currentReturnType = currentMethod.returnType.leafComponentType();
143                 if (!currentReturnType.isTypeVariable() || ((TypeVariableBinding) currentReturnType).declaringElement != currentMethod)
144                     problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
145             }
146         }
147     }
148
149     if (this.type.addSyntheticBridgeMethod(originalInherited, currentMethod.original()) != null) {
150         for (int i = 0, l = allInheritedMethods.length; i < l; i++) {
151             MethodBinding otherInheritedMethod = allInheritedMethods[i];
152             MethodBinding otherOriginal = otherInheritedMethod.original();
153             // only check inherited methods that are different & come from separate inheritance paths
154
if (otherOriginal == originalInherited || otherOriginal == otherInheritedMethod) continue;
155             if (inheritedMethod.areParametersEqual(otherInheritedMethod)) continue;
156             // skip it if otherInheritedMethod is defined by a subtype of inheritedMethod's declaringClass
157
if (otherInheritedMethod.declaringClass.erasure() != inheritedMethod.declaringClass.erasure())
158                 if (otherInheritedMethod.declaringClass.findSuperTypeWithSameErasure(inheritedMethod.declaringClass) != null)
159                     continue;
160             if (detectInheritedNameClash(originalInherited, otherOriginal))
161                 return;
162         }
163     }
164 }
165 void checkForNameClash(MethodBinding currentMethod, MethodBinding inheritedMethod) {
166     // sent from checkMethods() to compare a current method and an inherited method that are not 'equal'
167

168     // error cases:
169
// abstract class AA<E extends Comparable> { abstract void test(E element); }
170
// class A extends AA<Integer> { public void test(Integer i) {} }
171
// public class B extends A { public void test(Comparable i) {} }
172
// interface I<E extends Comparable> { void test(E element); }
173
// class A implements I<Integer> { public void test(Integer i) {} }
174
// public class B extends A { public void test(Comparable i) {} }
175

176     // abstract class Y implements EqualityComparable<Integer>, Equivalent<String> {
177
// public boolean equalTo(Integer other) { return true; }
178
// }
179
// interface Equivalent<T> { boolean equalTo(T other); }
180
// interface EqualityComparable<T> { boolean equalTo(T other); }
181

182     // class Y implements EqualityComparable, Equivalent<String>{
183
// public boolean equalTo(String other) { return true; }
184
// public boolean equalTo(Object other) { return true; }
185
// }
186
// interface Equivalent<T> { boolean equalTo(T other); }
187
// interface EqualityComparable { boolean equalTo(Object other); }
188

189     // class A<T extends Number> { void m(T t) {} }
190
// class B<S extends Integer> extends A<S> { void m(S t) {}}
191
// class D extends B<Integer> { void m(Number t) {} void m(Integer t) {} }
192

193     // inheritedMethods does not include I.test since A has a valid implementation
194
// interface I<E extends Comparable<E>> { void test(E element); }
195
// class A implements I<Integer> { public void test(Integer i) {} }
196
// class B extends A { public void test(Comparable i) {} }
197

198     if (currentMethod.declaringClass.isInterface() || currentMethod.isStatic()) return;
199
200     if (!detectNameClash(currentMethod, inheritedMethod)) { // check up the hierarchy for skipped inherited methods
201
TypeBinding[] currentParams = currentMethod.parameters;
202         TypeBinding[] inheritedParams = inheritedMethod.parameters;
203         int length = currentParams.length;
204         if (length != inheritedParams.length) return; // no match
205

206         for (int i = 0; i < length; i++)
207             if (currentParams[i] != inheritedParams[i])
208                 if (currentParams[i].isBaseType() != inheritedParams[i].isBaseType() || !inheritedParams[i].isCompatibleWith(currentParams[i]))
209                     return; // no chance that another inherited method's bridge method can collide
210

211         ReferenceBinding[] interfacesToVisit = null;
212         int nextPosition = 0;
213         ReferenceBinding superType = inheritedMethod.declaringClass;
214         ReferenceBinding[] itsInterfaces = superType.superInterfaces();
215         if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
216             nextPosition = itsInterfaces.length;
217             interfacesToVisit = itsInterfaces;
218         }
219         superType = superType.superclass(); // now start with its superclass
220
while (superType != null && superType.isValidBinding()) {
221             MethodBinding[] methods = superType.getMethods(currentMethod.selector);
222             for (int m = 0, n = methods.length; m < n; m++) {
223                 MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
224                 if (substitute != null && !doesSubstituteMethodOverride(currentMethod, substitute) && detectNameClash(currentMethod, substitute))
225                     return;
226             }
227             if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
228                 if (interfacesToVisit == null) {
229                     interfacesToVisit = itsInterfaces;
230                     nextPosition = interfacesToVisit.length;
231                 } else {
232                     int itsLength = itsInterfaces.length;
233                     if (nextPosition + itsLength >= interfacesToVisit.length)
234                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
235                     nextInterface : for (int a = 0; a < itsLength; a++) {
236                         ReferenceBinding next = itsInterfaces[a];
237                         for (int b = 0; b < nextPosition; b++)
238                             if (next == interfacesToVisit[b]) continue nextInterface;
239                         interfacesToVisit[nextPosition++] = next;
240                     }
241                 }
242             }
243             superType = superType.superclass();
244         }
245
246         for (int i = 0; i < nextPosition; i++) {
247             superType = interfacesToVisit[i];
248             if (superType.isValidBinding()) {
249                 MethodBinding[] methods = superType.getMethods(currentMethod.selector);
250                 for (int m = 0, n = methods.length; m < n; m++){
251                     MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
252                     if (substitute != null && !doesSubstituteMethodOverride(currentMethod, substitute) && detectNameClash(currentMethod, substitute))
253                         return;
254                 }
255                 if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
256                     int itsLength = itsInterfaces.length;
257                     if (nextPosition + itsLength >= interfacesToVisit.length)
258                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
259                     nextInterface : for (int a = 0; a < itsLength; a++) {
260                         ReferenceBinding next = itsInterfaces[a];
261                         for (int b = 0; b < nextPosition; b++)
262                             if (next == interfacesToVisit[b]) continue nextInterface;
263                         interfacesToVisit[nextPosition++] = next;
264                     }
265                 }
266             }
267         }
268     }
269 }
270 void checkInheritedMethods(MethodBinding inheritedMethod, MethodBinding otherInheritedMethod) {
271     // sent from checkMethods() to compare 2 inherited methods that are not 'equal'
272
if (inheritedMethod.declaringClass.erasure() == otherInheritedMethod.declaringClass.erasure()) {
273         if (inheritedMethod.areParameterErasuresEqual(otherInheritedMethod)) {
274             problemReporter().duplicateInheritedMethods(this.type, inheritedMethod, otherInheritedMethod);
275             return;
276         }
277     } else if (inheritedMethod.declaringClass.findSuperTypeWithSameErasure(otherInheritedMethod.declaringClass) != null) {
278         // skip it if inheritedMethod is defined by a subtype of otherInheritedMethod declaringClass
279
return;
280     }
281
282     // the 2 inherited methods clash because of a parameterized type overrides a raw type
283
// interface I { void foo(A a); }
284
// class Y { void foo(A<String> a) {} }
285
// abstract class X extends Y implements I { }
286
// class A<T> {}
287
// in this case the 2 inherited methods clash because of type variables
288
// interface I { <T, S> void foo(T t); }
289
// class Y { <T> void foo(T t) {} }
290
// abstract class X extends Y implements I {}
291

292     if (inheritedMethod.declaringClass.isInterface() || inheritedMethod.isStatic()) return;
293
294     detectInheritedNameClash(inheritedMethod.original(), otherInheritedMethod.original());
295 }
296 void checkInheritedMethods(MethodBinding[] methods, int length) {
297     int count = length;
298     int[] skip = new int[count];
299     nextMethod : for (int i = 0, l = length - 1; i < l; i++) {
300         if (skip[i] == -1) continue nextMethod;
301         MethodBinding method = methods[i];
302         MethodBinding[] duplicates = null;
303         for (int j = i + 1; j <= l; j++) {
304             MethodBinding method2 = methods[j];
305             if (method.declaringClass == method2.declaringClass && areMethodsCompatible(method, method2)) {
306                 skip[j] = -1;
307                 if (duplicates == null)
308                     duplicates = new MethodBinding[length];
309                 duplicates[j] = method2;
310             }
311         }
312         if (duplicates != null) {
313             // found an inherited ParameterizedType that defines duplicate methods
314
// if all methods are abstract or more than 1 concrete method exists, then consider them to be duplicates
315
// if a single concrete method 'implements' the abstract methods, then do not report a duplicate error
316
int concreteCount = method.isAbstract() ? 0 : 1;
317             MethodBinding methodToKeep = method; // if a concrete method exists, keep it, otherwise keep the first method
318
for (int m = 0, s = duplicates.length; m < s; m++) {
319                 if (duplicates[m] != null) {
320                     if (!duplicates[m].isAbstract()) {
321                         methodToKeep = duplicates[m];
322                         concreteCount++;
323                     }
324                 }
325             }
326             if (concreteCount != 1) {
327                 for (int m = 0, s = duplicates.length; m < s; m++) {
328                     if (duplicates[m] != null) {
329                         problemReporter().duplicateInheritedMethods(this.type, method, duplicates[m]);
330                         count--;
331                         if (methodToKeep == duplicates[m])
332                             methods[i] = null;
333                         else
334                             methods[m] = null;
335                     }
336                 }
337             }
338         }
339     }
340     if (count < length) {
341         if (count == 1) return; // no need to continue since only 1 inherited method is left
342
MethodBinding[] newMethods = new MethodBinding[count];
343         for (int i = length; --i >= 0;)
344             if (methods[i] != null)
345                 newMethods[--count] = methods[i];
346         methods = newMethods;
347         length = newMethods.length;
348     }
349
350     super.checkInheritedMethods(methods, length);
351 }
352 boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) {
353     // assumes length > 1
354
// its possible in 1.5 that A is compatible with B & C, but B is not compatible with C
355
int[] areIncompatible = null;
356     // abstract classes must check every method against each other
357
for (int i = 0, l = this.type.isAbstract() ? length - 2 : 0; i <= l;) {
358         MethodBinding method = methods[i++];
359         nextMethod : for (int j = i; j < length; j++) {
360             if (!areReturnTypesCompatible(method, methods[j])) {
361                 if (this.type.isInterface())
362                     for (int m = length; --m >= 0;)
363                         if (methods[m].declaringClass.id == TypeIds.T_JavaLangObject)
364                             continue nextMethod; // do not complain since the super interface already got blamed
365
// check to see if this is just a warning, if so report it & skip to next method
366
if (isUnsafeReturnTypeOverride(method, methods[j])) {
367                     problemReporter(method).unsafeReturnTypeOverride(method, methods[j], this.type);
368                     continue nextMethod;
369                 }
370                 if (areIncompatible == null)
371                     areIncompatible = new int[length];
372                 areIncompatible[i - 1] = -1;
373                 areIncompatible[j] = -1;
374             }
375         }
376     }
377     if (areIncompatible == null)
378         return true;
379
380     int count = 0;
381     for (int i = 0; i < length; i++)
382         if (areIncompatible[i] == -1) count++;
383     if (count == length) {
384         problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
385         return false;
386     }
387     MethodBinding[] methodsToReport = new MethodBinding[count];
388     for (int i = 0, index = 0; i < length; i++)
389         if (areIncompatible[i] == -1)
390             methodsToReport[index++] = methods[i];
391     problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methodsToReport, count);
392     return false;
393 }
394 void checkMethods() {
395     boolean mustImplementAbstractMethods = mustImplementAbstractMethods();
396     boolean skipInheritedMethods = mustImplementAbstractMethods && canSkipInheritedMethods(); // have a single concrete superclass so only check overridden methods
397
char[][] methodSelectors = this.inheritedMethods.keyTable;
398     nextSelector : for (int s = methodSelectors.length; --s >= 0;) {
399         if (methodSelectors[s] == null) continue nextSelector;
400
401         MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]);
402         if (current == null && skipInheritedMethods)
403             continue nextSelector;
404
405         MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s];
406         if (inherited.length == 1 && current == null) { // handle the common case
407
if (mustImplementAbstractMethods && inherited[0].isAbstract())
408                 checkAbstractMethod(inherited[0]);
409             continue nextSelector;
410         }
411
412         int index = -1;
413         MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
414         byte[] foundMatch = new byte[inherited.length];
415         if (current != null) {
416             for (int i = 0, length1 = current.length; i < length1; i++) {
417                 MethodBinding currentMethod = current[i];
418                 for (int j = 0, length2 = inherited.length; j < length2; j++) {
419                     MethodBinding inheritedMethod = computeSubstituteMethod(inherited[j], currentMethod);
420                     if (inheritedMethod != null) {
421                         if (foundMatch[j] == 0 && doesSubstituteMethodOverride(currentMethod, inheritedMethod)) {
422                             matchingInherited[++index] = inheritedMethod;
423                             foundMatch[j] = 1; // cannot null out inherited methods
424
} else {
425                             checkForNameClash(currentMethod, inheritedMethod);
426                         }
427                     }
428                 }
429                 if (index >= 0) {
430                     // see addtional comments in https://bugs.eclipse.org/bugs/show_bug.cgi?id=122881
431
// if (index > 0 && currentMethod.declaringClass.isInterface()) // only check when inherited methods are from interfaces
432
// checkInheritedReturnTypes(matchingInherited, index + 1);
433
checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1, inherited); // pass in the length of matching
434
while (index >= 0) matchingInherited[index--] = null; // clear the contents of the matching methods
435
}
436             }
437         }
438
439         for (int i = 0, length = inherited.length; i < length; i++) {
440             if (foundMatch[i] == 1) continue;
441
442             MethodBinding inheritedMethod = inherited[i];
443             matchingInherited[++index] = inheritedMethod;
444             for (int j = i + 1; j < length; j++) {
445                 MethodBinding otherInheritedMethod = inherited[j];
446                 if (foundMatch[j] == 1 || canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
447                     continue;
448                 otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
449                 if (otherInheritedMethod != null) {
450                     if (inheritedMethod.declaringClass != otherInheritedMethod.declaringClass
451                         && doesSubstituteMethodOverride(inheritedMethod, otherInheritedMethod)) {
452                             matchingInherited[++index] = otherInheritedMethod;
453                             foundMatch[j] = 1; // cannot null out inherited methods
454
} else {
455                         checkInheritedMethods(inheritedMethod, otherInheritedMethod);
456                     }
457                 }
458             }
459             if (index == -1) continue;
460
461             if (index > 0)
462                 checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
463
else if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract())
464                 checkAbstractMethod(matchingInherited[0]);
465             while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
466
}
467     }
468 }
469 void checkTypeVariableMethods(TypeParameter typeParameter) {
470     char[][] methodSelectors = this.inheritedMethods.keyTable;
471     nextSelector : for (int s = methodSelectors.length; --s >= 0;) {
472         if (methodSelectors[s] == null) continue nextSelector;
473         MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s];
474         if (inherited.length == 1) continue nextSelector;
475
476         int index = -1;
477         MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
478         for (int i = 0, length = inherited.length; i < length; i++) {
479             while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
480
MethodBinding inheritedMethod = inherited[i];
481             if (inheritedMethod != null) {
482                 matchingInherited[++index] = inheritedMethod;
483                 for (int j = i + 1; j < length; j++) {
484                     MethodBinding otherInheritedMethod = inherited[j];
485                     if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
486                         continue;
487                     otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
488                     if (otherInheritedMethod != null && doesSubstituteMethodOverride(inheritedMethod, otherInheritedMethod)) {
489                         matchingInherited[++index] = otherInheritedMethod;
490                         inherited[j] = null; // do not want to find it again
491
}
492                 }
493             }
494             if (index > 0) {
495                 MethodBinding first = matchingInherited[0];
496                 int count = index + 1;
497                 while (--count > 0 && areReturnTypesCompatible(first, matchingInherited[count])){/*empty*/}
498                 if (count > 0) { // All inherited methods do NOT have the same vmSignature
499
problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(typeParameter, matchingInherited, index + 1);
500                     continue nextSelector;
501                 }
502             }
503         }
504     }
505 }
506 MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod) {
507     if (inheritedMethod == null) return null;
508     if (currentMethod.parameters.length != inheritedMethod.parameters.length) return null; // no match
509

510     // due to hierarchy & compatibility checks, we need to ensure these 2 methods are resolved
511
if (currentMethod.declaringClass instanceof BinaryTypeBinding)
512         ((BinaryTypeBinding) currentMethod.declaringClass).resolveTypesFor(currentMethod);
513     if (inheritedMethod.declaringClass instanceof BinaryTypeBinding)
514         ((BinaryTypeBinding) inheritedMethod.declaringClass).resolveTypesFor(inheritedMethod);
515
516     TypeVariableBinding[] inheritedTypeVariables = inheritedMethod.typeVariables;
517     if (inheritedTypeVariables == Binding.NO_TYPE_VARIABLES) return inheritedMethod;
518     int inheritedLength = inheritedTypeVariables.length;
519     TypeVariableBinding[] typeVariables = currentMethod.typeVariables;
520     int length = typeVariables.length;
521     if (length > 0 && inheritedLength != length) return inheritedMethod; // no match JLS 8.4.2
522
TypeBinding[] arguments = new TypeBinding[inheritedLength];
523     if (inheritedLength <= length) {
524         System.arraycopy(typeVariables, 0, arguments, 0, inheritedLength);
525     } else {
526         System.arraycopy(typeVariables, 0, arguments, 0, length);
527         for (int i = length; i < inheritedLength; i++)
528             arguments[i] = inheritedTypeVariables[i].upperBound();
529     }
530     ParameterizedGenericMethodBinding substitute =
531         this.environment.createParameterizedGenericMethod(inheritedMethod, arguments);
532
533     // interface I { <T> void foo(T t); }
534
// class X implements I { public <T extends I> void foo(T t) {} }
535
// for the above case, we do not want to answer the substitute method since its not a match
536
for (int i = 0; i < inheritedLength; i++) {
537         TypeVariableBinding inheritedTypeVariable = inheritedTypeVariables[i];
538         TypeBinding argument = arguments[i];
539         if (argument instanceof TypeVariableBinding) {
540             TypeVariableBinding typeVariable = (TypeVariableBinding) argument;
541             if (typeVariable.firstBound == inheritedTypeVariable.firstBound) {
542                 if (typeVariable.firstBound == null)
543                     continue; // both are null
544
} else if (typeVariable.firstBound != null && inheritedTypeVariable.firstBound != null) {
545                 if (typeVariable.firstBound.isClass() != inheritedTypeVariable.firstBound.isClass())
546                     return inheritedMethod; // not a match
547
}
548             if (Scope.substitute(substitute, inheritedTypeVariable.superclass) != typeVariable.superclass)
549                 return inheritedMethod; // not a match
550
int interfaceLength = inheritedTypeVariable.superInterfaces.length;
551             ReferenceBinding[] interfaces = typeVariable.superInterfaces;
552             if (interfaceLength != interfaces.length)
553                 return inheritedMethod; // not a match
554
// TODO (kent) another place where we expect the superinterfaces to be in the exact same order
555
next : for (int j = 0; j < interfaceLength; j++) {
556                 TypeBinding superType = Scope.substitute(substitute, inheritedTypeVariable.superInterfaces[j]);
557                 for (int k = 0; k < interfaceLength; k++)
558                     if (superType == interfaces[k])
559                         continue next;
560                 return inheritedMethod; // not a match
561
}
562         } else if (inheritedTypeVariable.boundCheck(substitute, argument) != TypeConstants.OK) {
563                 return inheritedMethod;
564         }
565     }
566    return substitute;
567 }
568 boolean detectInheritedNameClash(MethodBinding inherited, MethodBinding otherInherited) {
569     if (!inherited.areParameterErasuresEqual(otherInherited) || inherited.returnType.erasure() != otherInherited.returnType.erasure()) return false;
570
571     problemReporter().inheritedMethodsHaveNameClash(this.type, inherited, otherInherited);
572     return true;
573 }
574 boolean detectNameClash(MethodBinding current, MethodBinding inherited) {
575     MethodBinding original = inherited.original(); // can be the same as inherited
576
if (!current.areParameterErasuresEqual(original) || current.returnType.erasure() != original.returnType.erasure()) return false;
577
578     problemReporter(current).methodNameClash(current,
579             inherited.declaringClass.isRawType() ? inherited : original);
580     return true;
581 }
582 public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
583     MethodBinding substitute = computeSubstituteMethod(inheritedMethod, method);
584     return substitute != null && doesSubstituteMethodOverride(method, substitute);
585 }
586 // if method "overrides" substituteMethod then we can skip over substituteMethod while resolving a message send
587
// if it does not then a name clash error is likely
588
boolean doesSubstituteMethodOverride(MethodBinding method, MethodBinding substituteMethod) {
589     if (!areParametersEqual(method, substituteMethod)) {
590         // method can still override substituteMethod in cases like :
591
// <U extends Number> void c(U u) {}
592
// @Override void c(Number n) {}
593
// but method cannot have a "generic-enabled" parameter type
594
if (substituteMethod.hasSubstitutedParameters() && method.areParameterErasuresEqual(substituteMethod))
595             return method.typeVariables == Binding.NO_TYPE_VARIABLES && !hasGenericParameter(method);
596         return false;
597     }
598
599     if (substituteMethod instanceof ParameterizedGenericMethodBinding) {
600         // since substituteMethod has substituted type variables, method cannot have a generic signature AND no variables -> its a name clash if it does
601
return ! (hasGenericParameter(method) && method.typeVariables == Binding.NO_TYPE_VARIABLES);
602     }
603
604     // if method has its own variables, then substituteMethod failed bounds check in computeSubstituteMethod()
605
return method.typeVariables == Binding.NO_TYPE_VARIABLES;
606 }
607 boolean hasGenericParameter(MethodBinding method) {
608     if (method.genericSignature() == null) return false;
609
610     // may be only the return type that is generic, need to check parameters
611
TypeBinding[] params = method.parameters;
612     for (int i = 0, l = params.length; i < l; i++) {
613         TypeBinding param = params[i].leafComponentType();
614         if (param instanceof ReferenceBinding) {
615             int modifiers = ((ReferenceBinding) param).modifiers;
616             if ((modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)
617                 return true;
618         }
619     }
620     return false;
621 }
622 boolean doTypeVariablesClash(MethodBinding one, MethodBinding substituteTwo) {
623     // one has type variables and substituteTwo did not pass bounds check in computeSubstituteMethod()
624
return one.typeVariables != Binding.NO_TYPE_VARIABLES && !(substituteTwo instanceof ParameterizedGenericMethodBinding);
625 }
626 SimpleSet findSuperinterfaceCollisions(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) {
627     ReferenceBinding[] interfacesToVisit = null;
628     int nextPosition = 0;
629     ReferenceBinding[] itsInterfaces = superInterfaces;
630     if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
631         nextPosition = itsInterfaces.length;
632         interfacesToVisit = itsInterfaces;
633     }
634
635     boolean isInconsistent = this.type.isHierarchyInconsistent();
636     ReferenceBinding superType = superclass;
637     while (superType != null && superType.isValidBinding()) {
638         isInconsistent |= superType.isHierarchyInconsistent();
639         if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
640             if (interfacesToVisit == null) {
641                 interfacesToVisit = itsInterfaces;
642                 nextPosition = interfacesToVisit.length;
643             } else {
644                 int itsLength = itsInterfaces.length;
645                 if (nextPosition + itsLength >= interfacesToVisit.length)
646                     System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
647                 nextInterface : for (int a = 0; a < itsLength; a++) {
648                     ReferenceBinding next = itsInterfaces[a];
649                     for (int b = 0; b < nextPosition; b++)
650                         if (next == interfacesToVisit[b]) continue nextInterface;
651                     interfacesToVisit[nextPosition++] = next;
652                 }
653             }
654         }
655         superType = superType.superclass();
656     }
657
658     for (int i = 0; i < nextPosition; i++) {
659         superType = interfacesToVisit[i];
660         if (superType.isValidBinding()) {
661             isInconsistent |= superType.isHierarchyInconsistent();
662             if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
663                 int itsLength = itsInterfaces.length;
664                 if (nextPosition + itsLength >= interfacesToVisit.length)
665                     System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
666                 nextInterface : for (int a = 0; a < itsLength; a++) {
667                     ReferenceBinding next = itsInterfaces[a];
668                     for (int b = 0; b < nextPosition; b++)
669                         if (next == interfacesToVisit[b]) continue nextInterface;
670                     interfacesToVisit[nextPosition++] = next;
671                 }
672             }
673         }
674     }
675
676     if (!isInconsistent) return null; // hierarchy is consistent so no collisions are possible
677
SimpleSet copy = null;
678     for (int i = 0; i < nextPosition; i++) {
679         ReferenceBinding current = interfacesToVisit[i];
680         if (current.isValidBinding()) {
681             TypeBinding erasure = current.erasure();
682             for (int j = i + 1; j < nextPosition; j++) {
683                 ReferenceBinding next = interfacesToVisit[j];
684                 if (next.isValidBinding() && next.erasure() == erasure) {
685                     if (copy == null)
686                         copy = new SimpleSet(nextPosition);
687                     copy.add(interfacesToVisit[i]);
688                     copy.add(interfacesToVisit[j]);
689                 }
690             }
691         }
692     }
693     return copy;
694 }
695 // caveat: returns false if a method is implemented that needs a bridge method
696
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
697     if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
698         return false; // must hold onto ParameterizedMethod to see if a bridge method is necessary
699

700     inheritedMethod = computeSubstituteMethod(inheritedMethod, existingMethod);
701     return inheritedMethod != null
702         && inheritedMethod.returnType == existingMethod.returnType // keep around to produce bridge methods
703
&& super.isInterfaceMethodImplemented(inheritedMethod, existingMethod, superType);
704 }
705 boolean isUnsafeReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
706     // JLS 3 §8.4.5: more are accepted, with an unchecked conversion
707
if (currentMethod.returnType == inheritedMethod.returnType.erasure()) {
708         TypeBinding[] currentParams = currentMethod.parameters;
709         TypeBinding[] inheritedParams = inheritedMethod.parameters;
710         for (int i = 0, l = currentParams.length; i < l; i++)
711             if (!areTypesEqual(currentParams[i], inheritedParams[i]))
712                 return true;
713     }
714     if (currentMethod.typeVariables == Binding.NO_TYPE_VARIABLES
715         && inheritedMethod.original().typeVariables != Binding.NO_TYPE_VARIABLES
716         && currentMethod.returnType.erasure().findSuperTypeWithSameErasure(inheritedMethod.returnType.erasure()) != null) {
717             return true;
718     }
719     return false;
720 }
721 boolean reportIncompatibleReturnTypeError(MethodBinding currentMethod, MethodBinding inheritedMethod) {
722     if (isUnsafeReturnTypeOverride(currentMethod, inheritedMethod)) {
723         problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, inheritedMethod, this.type);
724         return false;
725     }
726     return super.reportIncompatibleReturnTypeError(currentMethod, inheritedMethod);
727 }
728 void verify(SourceTypeBinding someType) {
729     if (someType.isAnnotationType())
730         someType.detectAnnotationCycle();
731
732     super.verify(someType);
733
734     for (int i = someType.typeVariables.length; --i >= 0;) {
735         TypeVariableBinding var = someType.typeVariables[i];
736         // must verify bounds if the variable has more than 1
737
if (var.superInterfaces == Binding.NO_SUPERINTERFACES) continue;
738         if (var.superInterfaces.length == 1 && var.superclass.id == TypeIds.T_JavaLangObject) continue;
739
740         this.currentMethods = new HashtableOfObject(0);
741         ReferenceBinding superclass = var.superclass();
742         if (superclass.kind() == Binding.TYPE_PARAMETER)
743             superclass = (ReferenceBinding) superclass.erasure();
744         ReferenceBinding[] itsInterfaces = var.superInterfaces();
745         ReferenceBinding[] superInterfaces = new ReferenceBinding[itsInterfaces.length];
746         for (int j = itsInterfaces.length; --j >= 0;) {
747             superInterfaces[j] = itsInterfaces[j].kind() == Binding.TYPE_PARAMETER
748                 ? (ReferenceBinding) itsInterfaces[j].erasure()
749                 : itsInterfaces[j];
750         }
751         computeInheritedMethods(superclass, superInterfaces);
752         checkTypeVariableMethods(someType.scope.referenceContext.typeParameters[i]);
753     }
754 }
755 }
756
Popular Tags