001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.compiler.lookup;
011:
012: import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
013: import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
014: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
015: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
016: import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
017: import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
018: import org.eclipse.jdt.internal.compiler.util.SimpleSet;
019:
020: public class MethodVerifier {
021: SourceTypeBinding type;
022: HashtableOfObject inheritedMethods;
023: HashtableOfObject currentMethods;
024: LookupEnvironment environment;
025: private boolean allowCompatibleReturnTypes;
026:
027: /*
028: Binding creation is responsible for reporting all problems with types:
029: - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final)
030: - plus invalid modifiers given the context (the verifier did not do this before)
031: - qualified name collisions between a type and a package (types in default packages are excluded)
032: - all type hierarchy problems:
033: - cycles in the superclass or superinterface hierarchy
034: - an ambiguous, invisible or missing superclass or superinterface
035: - extending a final class
036: - extending an interface instead of a class
037: - implementing a class instead of an interface
038: - implementing the same interface more than once (ie. duplicate interfaces)
039: - with nested types:
040: - shadowing an enclosing type's source name
041: - defining a static class or interface inside a non-static nested class
042: - defining an interface as a local type (local types can only be classes)
043: */
044: MethodVerifier(LookupEnvironment environment) {
045: this .type = null; // Initialized with the public method verify(SourceTypeBinding)
046: this .inheritedMethods = null;
047: this .currentMethods = null;
048: this .environment = environment;
049: this .allowCompatibleReturnTypes = environment.globalOptions.complianceLevel >= ClassFileConstants.JDK1_5
050: && environment.globalOptions.sourceLevel < ClassFileConstants.JDK1_5;
051: }
052:
053: boolean areMethodsCompatible(MethodBinding one, MethodBinding two) {
054: return doesMethodOverride(one, two)
055: && areReturnTypesCompatible(one, two);
056: }
057:
058: boolean areParametersEqual(MethodBinding one, MethodBinding two) {
059: TypeBinding[] oneArgs = one.parameters;
060: TypeBinding[] twoArgs = two.parameters;
061: if (oneArgs == twoArgs)
062: return true;
063:
064: int length = oneArgs.length;
065: if (length != twoArgs.length)
066: return false;
067:
068: for (int i = 0; i < length; i++)
069: if (!areTypesEqual(oneArgs[i], twoArgs[i]))
070: return false;
071: return true;
072: }
073:
074: boolean areReturnTypesCompatible(MethodBinding one,
075: MethodBinding two) {
076: if (one.returnType == two.returnType)
077: return true;
078:
079: if (areTypesEqual(one.returnType, two.returnType))
080: return true;
081:
082: // when sourceLevel < 1.5 but compliance >= 1.5, allow return types in binaries to be compatible instead of just equal
083: if (this .allowCompatibleReturnTypes
084: && one.declaringClass instanceof BinaryTypeBinding
085: && two.declaringClass instanceof BinaryTypeBinding) {
086: return areReturnTypesCompatible0(one, two);
087: }
088: return false;
089: }
090:
091: boolean areReturnTypesCompatible0(MethodBinding one,
092: MethodBinding two) {
093: // short is compatible with int, but as far as covariance is concerned, its not
094: if (one.returnType.isBaseType())
095: return false;
096:
097: if (!one.declaringClass.isInterface()) {
098: if (one.declaringClass.id == TypeIds.T_JavaLangObject)
099: return two.returnType.isCompatibleWith(one.returnType); // interface methods inherit from Object
100: return one.returnType.isCompatibleWith(two.returnType);
101: }
102:
103: // check for methods from Object, every interface inherits from Object
104: if (two.declaringClass.id == TypeIds.T_JavaLangObject)
105: return one.returnType.isCompatibleWith(two.returnType);
106:
107: // both are interfaces, see if they're related
108: if (one.declaringClass.implements Interface(two.declaringClass,
109: true))
110: return one.returnType.isCompatibleWith(two.returnType);
111: if (two.declaringClass.implements Interface(one.declaringClass,
112: true))
113: return two.returnType.isCompatibleWith(one.returnType);
114:
115: // unrelated interfaces... one must be a subtype of the other
116: return one.returnType.isCompatibleWith(two.returnType)
117: || two.returnType.isCompatibleWith(one.returnType);
118: }
119:
120: boolean areTypesEqual(TypeBinding one, TypeBinding two) {
121: if (one == two)
122: return true;
123:
124: // its possible that an UnresolvedReferenceBinding can be compared to its resolved type
125: // when they're both UnresolvedReferenceBindings then they must be identical like all other types
126: // all wrappers of UnresolvedReferenceBindings are converted as soon as the type is resolved
127: // so its not possible to have 2 arrays where one is UnresolvedX[] and the other is X[]
128: if (one instanceof UnresolvedReferenceBinding)
129: return ((UnresolvedReferenceBinding) one).resolvedType == two;
130: if (two instanceof UnresolvedReferenceBinding)
131: return ((UnresolvedReferenceBinding) two).resolvedType == one;
132: return false; // all other type bindings are identical
133: }
134:
135: boolean canSkipInheritedMethods() {
136: if (this .type.super class() != null
137: && this .type.super class().isAbstract())
138: return false;
139: return this .type.super Interfaces() == Binding.NO_SUPERINTERFACES;
140: }
141:
142: boolean canSkipInheritedMethods(MethodBinding one, MethodBinding two) {
143: return two == null // already know one is not null
144: || one.declaringClass == two.declaringClass;
145: }
146:
147: void checkAbstractMethod(MethodBinding abstractMethod) {
148: if (mustImplementAbstractMethod(abstractMethod.declaringClass)) {
149: TypeDeclaration typeDeclaration = this .type.scope.referenceContext;
150: if (typeDeclaration != null) {
151: MethodDeclaration missingAbstractMethod = typeDeclaration
152: .addMissingAbstractMethodFor(abstractMethod);
153: missingAbstractMethod.scope.problemReporter()
154: .abstractMethodMustBeImplemented(this .type,
155: abstractMethod);
156: } else {
157: problemReporter().abstractMethodMustBeImplemented(
158: this .type, abstractMethod);
159: }
160: }
161: }
162:
163: void checkAgainstInheritedMethods(MethodBinding currentMethod,
164: MethodBinding[] methods, int length,
165: MethodBinding[] allInheritedMethods) {
166: if (this .type.isAnnotationType()) { // annotation cannot override any method
167: problemReporter().annotationCannotOverrideMethod(
168: currentMethod, methods[length - 1]);
169: return; // do not repoort against subsequent inherited methods
170: }
171: CompilerOptions options = type.scope.compilerOptions();
172: // need to find the overridden methods to avoid blaming this type for issues which are already reported against a supertype
173: // but cannot ignore an overridden inherited method completely when it comes to checking for bridge methods
174: int[] overriddenInheritedMethods = length > 1 ? findOverriddenInheritedMethods(
175: methods, length)
176: : null;
177: nextMethod: for (int i = length; --i >= 0;) {
178: MethodBinding inheritedMethod = methods[i];
179: if (overriddenInheritedMethods == null
180: || overriddenInheritedMethods[i] == 0) {
181: if (currentMethod.isStatic() != inheritedMethod
182: .isStatic()) { // Cannot override a static method or hide an instance method
183: problemReporter(currentMethod)
184: .staticAndInstanceConflict(currentMethod,
185: inheritedMethod);
186: continue nextMethod;
187: }
188:
189: // want to tag currentMethod even if return types are not equal
190: if (inheritedMethod.isAbstract()) {
191: if (inheritedMethod.declaringClass.isInterface()) {
192: currentMethod.modifiers |= ExtraCompilerModifiers.AccImplementing;
193: } else {
194: currentMethod.modifiers |= ExtraCompilerModifiers.AccImplementing
195: | ExtraCompilerModifiers.AccOverriding;
196: }
197: // with the above change an abstract method is tagged as implementing the inherited abstract method
198: // if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) {
199: // if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0)
200: // currentMethod.modifiers |= CompilerModifiers.AccImplementing;
201: } else {
202: currentMethod.modifiers |= ExtraCompilerModifiers.AccOverriding;
203: }
204:
205: if (!areReturnTypesCompatible(currentMethod,
206: inheritedMethod))
207: if (reportIncompatibleReturnTypeError(
208: currentMethod, inheritedMethod))
209: continue nextMethod;
210:
211: if (currentMethod.thrownExceptions != Binding.NO_EXCEPTIONS)
212: checkExceptions(currentMethod, inheritedMethod);
213: if (inheritedMethod.isFinal())
214: problemReporter(currentMethod)
215: .finalMethodCannotBeOverridden(
216: currentMethod, inheritedMethod);
217: if (!isAsVisible(currentMethod, inheritedMethod))
218: problemReporter(currentMethod).visibilityConflict(
219: currentMethod, inheritedMethod);
220: if (options.reportDeprecationWhenOverridingDeprecatedMethod
221: && inheritedMethod.isViewedAsDeprecated()) {
222: if (!currentMethod.isViewedAsDeprecated()
223: || options.reportDeprecationInsideDeprecatedCode) {
224: // check against the other inherited methods to see if they hide this inheritedMethod
225: ReferenceBinding declaringClass = inheritedMethod.declaringClass;
226: if (declaringClass.isInterface())
227: for (int j = length; --j >= 0;)
228: if (i != j
229: && methods[j].declaringClass
230: .implements Interface(
231: declaringClass,
232: false))
233: continue nextMethod;
234:
235: problemReporter(currentMethod)
236: .overridesDeprecatedMethod(
237: currentMethod, inheritedMethod);
238: }
239: }
240: }
241: checkForBridgeMethod(currentMethod, inheritedMethod,
242: allInheritedMethods);
243: }
244: }
245:
246: void checkConcreteInheritedMethod(MethodBinding concreteMethod,
247: MethodBinding[] abstractMethods) {
248: // Remember that interfaces can only define public instance methods
249: if (concreteMethod.isStatic())
250: // Cannot inherit a static method which is specified as an instance method by an interface
251: problemReporter().staticInheritedMethodConflicts(type,
252: concreteMethod, abstractMethods);
253: if (!concreteMethod.isPublic()) {
254: int index = 0, length = abstractMethods.length;
255: if (concreteMethod.isProtected()) {
256: for (; index < length; index++)
257: if (abstractMethods[index].isPublic())
258: break;
259: } else if (concreteMethod.isDefault()) {
260: for (; index < length; index++)
261: if (!abstractMethods[index].isDefault())
262: break;
263: }
264: if (index < length)
265: problemReporter().inheritedMethodReducesVisibility(
266: type, concreteMethod, abstractMethods);
267: }
268: if (concreteMethod.thrownExceptions != Binding.NO_EXCEPTIONS)
269: for (int i = abstractMethods.length; --i >= 0;)
270: checkExceptions(concreteMethod, abstractMethods[i]);
271: }
272:
273: /*
274: "8.4.4"
275: Verify that newExceptions are all included in inheritedExceptions.
276: Assumes all exceptions are valid and throwable.
277: Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203).
278: */
279: void checkExceptions(MethodBinding newMethod,
280: MethodBinding inheritedMethod) {
281: ReferenceBinding[] newExceptions = resolvedExceptionTypesFor(newMethod);
282: ReferenceBinding[] inheritedExceptions = resolvedExceptionTypesFor(inheritedMethod);
283: for (int i = newExceptions.length; --i >= 0;) {
284: ReferenceBinding newException = newExceptions[i];
285: int j = inheritedExceptions.length;
286: while (--j > -1
287: && !isSameClassOrSubclassOf(newException,
288: inheritedExceptions[j])) {/*empty*/
289: }
290: if (j == -1)
291: if (!newException.isUncheckedException(false))
292: problemReporter(newMethod)
293: .incompatibleExceptionInThrowsClause(
294: this .type, newMethod,
295: inheritedMethod, newException);
296: }
297: }
298:
299: void checkForBridgeMethod(MethodBinding currentMethod,
300: MethodBinding inheritedMethod,
301: MethodBinding[] allInheritedMethods) {
302: // no op before 1.5
303: }
304:
305: void checkInheritedMethods(MethodBinding[] methods, int length) {
306: if (length > 1) {
307: int[] overriddenInheritedMethods = findOverriddenInheritedMethods(
308: methods, length);
309: if (overriddenInheritedMethods != null) {
310: // detected some overridden methods that can be ignored when checking return types
311: // but cannot ignore an overridden inherited method completely when it comes to checking for bridge methods
312: int index = 0;
313: MethodBinding[] closestMethods = new MethodBinding[length];
314: for (int i = 0; i < length; i++)
315: if (overriddenInheritedMethods[i] == 0)
316: closestMethods[index++] = methods[i];
317: if (index > 1
318: && !checkInheritedReturnTypes(closestMethods,
319: index))
320: return;
321: } else if (!checkInheritedReturnTypes(methods, length)) {
322: return;
323: }
324: }
325:
326: MethodBinding concreteMethod = null;
327: if (!type.isInterface()) { // ignore concrete methods for interfaces
328: for (int i = length; --i >= 0;) { // Remember that only one of the methods can be non-abstract
329: if (!methods[i].isAbstract()) {
330: concreteMethod = methods[i];
331: break;
332: }
333: }
334: }
335: if (concreteMethod == null) {
336: if (!this .type.isAbstract()) {
337: for (int i = length; --i >= 0;) {
338: if (mustImplementAbstractMethod(methods[i].declaringClass)) {
339: TypeDeclaration typeDeclaration = this .type.scope.referenceContext;
340: if (typeDeclaration != null) {
341: MethodDeclaration missingAbstractMethod = typeDeclaration
342: .addMissingAbstractMethodFor(methods[0]);
343: missingAbstractMethod.scope
344: .problemReporter()
345: .abstractMethodMustBeImplemented(
346: this .type, methods[0]);
347: } else {
348: problemReporter()
349: .abstractMethodMustBeImplemented(
350: this .type, methods[0]);
351: }
352: return;
353: }
354: }
355: }
356: return;
357: }
358:
359: if (length > 1) {
360: MethodBinding[] abstractMethods = new MethodBinding[length - 1];
361: int index = 0;
362: for (int i = length; --i >= 0;)
363: if (methods[i] != concreteMethod)
364: abstractMethods[index++] = methods[i];
365: checkConcreteInheritedMethod(concreteMethod,
366: abstractMethods);
367: }
368: }
369:
370: boolean checkInheritedReturnTypes(MethodBinding[] methods,
371: int length) {
372: MethodBinding first = methods[0];
373: int index = length;
374: while (--index > 0
375: && areReturnTypesCompatible(first, methods[index])) {/*empty*/
376: }
377: if (index == 0)
378: return true;
379:
380: // All inherited methods do NOT have the same vmSignature
381: if (this .type.isInterface())
382: for (int i = length; --i >= 0;)
383: if (methods[i].declaringClass.id == TypeIds.T_JavaLangObject)
384: return false; // do not complain since the super interface already got blamed
385: problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(
386: this .type, methods, length);
387: return false;
388: }
389:
390: /*
391: For each inherited method identifier (message pattern - vm signature minus the return type)
392: if current method exists
393: if current's vm signature does not match an inherited signature then complain
394: else compare current's exceptions & visibility against each inherited method
395: else
396: if inherited methods = 1
397: if inherited is abstract && type is NOT an interface or abstract, complain
398: else
399: if vm signatures do not match complain
400: else
401: find the concrete implementation amongst the abstract methods (can only be 1)
402: if one exists then
403: it must be a public instance method
404: compare concrete's exceptions against each abstract method
405: else
406: complain about missing implementation only if type is NOT an interface or abstract
407: */
408: void checkMethods() {
409: boolean mustImplementAbstractMethods = mustImplementAbstractMethods();
410: boolean skipInheritedMethods = mustImplementAbstractMethods
411: && canSkipInheritedMethods(); // have a single concrete superclass so only check overridden methods
412: char[][] methodSelectors = this .inheritedMethods.keyTable;
413: nextSelector: for (int s = methodSelectors.length; --s >= 0;) {
414: if (methodSelectors[s] == null)
415: continue nextSelector;
416:
417: MethodBinding[] current = (MethodBinding[]) this .currentMethods
418: .get(methodSelectors[s]);
419: if (current == null && skipInheritedMethods)
420: continue nextSelector;
421:
422: MethodBinding[] inherited = (MethodBinding[]) this .inheritedMethods.valueTable[s];
423: if (inherited.length == 1 && current == null) { // handle the common case
424: if (mustImplementAbstractMethods
425: && inherited[0].isAbstract())
426: checkAbstractMethod(inherited[0]);
427: continue nextSelector;
428: }
429:
430: int index = -1;
431: MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
432: if (current != null) {
433: for (int i = 0, length1 = current.length; i < length1; i++) {
434: MethodBinding currentMethod = current[i];
435: for (int j = 0, length2 = inherited.length; j < length2; j++) {
436: MethodBinding inheritedMethod = computeSubstituteMethod(
437: inherited[j], currentMethod);
438: if (inheritedMethod != null) {
439: if (doesMethodOverride(currentMethod,
440: inheritedMethod)) {
441: matchingInherited[++index] = inheritedMethod;
442: inherited[j] = null; // do not want to find it again
443: }
444: }
445: }
446: if (index >= 0) {
447: checkAgainstInheritedMethods(currentMethod,
448: matchingInherited, index + 1, inherited); // pass in the length of matching
449: while (index >= 0)
450: matchingInherited[index--] = null; // clear the contents of the matching methods
451: }
452: }
453: }
454:
455: for (int i = 0, length = inherited.length; i < length; i++) {
456: MethodBinding inheritedMethod = inherited[i];
457: if (inheritedMethod == null)
458: continue;
459:
460: matchingInherited[++index] = inheritedMethod;
461: for (int j = i + 1; j < length; j++) {
462: MethodBinding otherInheritedMethod = inherited[j];
463: if (canSkipInheritedMethods(inheritedMethod,
464: otherInheritedMethod))
465: continue;
466: otherInheritedMethod = computeSubstituteMethod(
467: otherInheritedMethod, inheritedMethod);
468: if (otherInheritedMethod != null) {
469: if (doesMethodOverride(inheritedMethod,
470: otherInheritedMethod)) {
471: matchingInherited[++index] = otherInheritedMethod;
472: inherited[j] = null; // do not want to find it again
473: }
474: }
475: }
476: if (index == -1)
477: continue;
478: if (index > 0)
479: checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
480: else if (mustImplementAbstractMethods
481: && matchingInherited[0].isAbstract())
482: checkAbstractMethod(matchingInherited[0]);
483: while (index >= 0)
484: matchingInherited[index--] = null; // clear the contents of the matching methods
485: }
486: }
487: }
488:
489: void checkPackagePrivateAbstractMethod(MethodBinding abstractMethod) {
490: // check that the inherited abstract method (package private visibility) is implemented within the same package
491: PackageBinding necessaryPackage = abstractMethod.declaringClass.fPackage;
492: if (necessaryPackage == this .type.fPackage)
493: return; // not a problem
494:
495: ReferenceBinding super Type = this .type.super class();
496: char[] selector = abstractMethod.selector;
497: do {
498: if (!super Type.isValidBinding())
499: return;
500: if (!super Type.isAbstract())
501: return; // closer non abstract super type will be flagged instead
502:
503: if (necessaryPackage == super Type.fPackage) {
504: MethodBinding[] methods = super Type
505: .getMethods(selector);
506: nextMethod: for (int m = methods.length; --m >= 0;) {
507: MethodBinding method = methods[m];
508: if (method.isPrivate() || method.isConstructor()
509: || method.isDefaultAbstract())
510: continue nextMethod;
511: if (areMethodsCompatible(method, abstractMethod))
512: return; // found concrete implementation of abstract method in same package
513: }
514: }
515: } while ((super Type = super Type.super class()) != abstractMethod.declaringClass);
516:
517: // non visible abstract methods cannot be overridden so the type must be defined abstract
518: problemReporter().abstractMethodCannotBeOverridden(this .type,
519: abstractMethod);
520: }
521:
522: void computeInheritedMethods() {
523: ReferenceBinding super class = this .type.isInterface() ? this .type.scope
524: .getJavaLangObject() // check interface methods against Object
525: : this .type.super class(); // class or enum
526: computeInheritedMethods(super class, type.super Interfaces());
527: }
528:
529: /*
530: Binding creation is responsible for reporting:
531: - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations)
532: - plus invalid modifiers given the context... examples:
533: - interface methods can only be public
534: - abstract methods can only be defined by abstract classes
535: - collisions... 2 methods with identical vmSelectors
536: - multiple methods with the same message pattern but different return types
537: - ambiguous, invisible or missing return/argument/exception types
538: - check the type of any array is not void
539: - check that each exception type is Throwable or a subclass of it
540: */
541: void computeInheritedMethods(ReferenceBinding super class,
542: ReferenceBinding[] super Interfaces) {
543: // only want to remember inheritedMethods that can have an impact on the current type
544: // if an inheritedMethod has been 'replaced' by a supertype's method then skip it
545:
546: this .inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type
547: ReferenceBinding[] interfacesToVisit = null;
548: int nextPosition = 0;
549: ReferenceBinding[] itsInterfaces = super Interfaces;
550: if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
551: nextPosition = itsInterfaces.length;
552: interfacesToVisit = itsInterfaces;
553: }
554:
555: ReferenceBinding super Type = super class;
556: HashtableOfObject nonVisibleDefaultMethods = new HashtableOfObject(
557: 3); // maps method selectors to an array of methods
558: boolean allSuperclassesAreAbstract = true;
559:
560: while (super Type != null && super Type.isValidBinding()) {
561: if (allSuperclassesAreAbstract) {
562: if (super Type.isAbstract()) {
563: // only need to include superinterfaces if immediate superclasses are abstract
564: if ((itsInterfaces = super Type.super Interfaces()) != Binding.NO_SUPERINTERFACES) {
565: if (interfacesToVisit == null) {
566: interfacesToVisit = itsInterfaces;
567: nextPosition = interfacesToVisit.length;
568: } else {
569: int itsLength = itsInterfaces.length;
570: if (nextPosition + itsLength >= interfacesToVisit.length)
571: System
572: .arraycopy(
573: interfacesToVisit,
574: 0,
575: interfacesToVisit = new ReferenceBinding[nextPosition
576: + itsLength + 5],
577: 0, nextPosition);
578: nextInterface: for (int a = 0; a < itsLength; a++) {
579: ReferenceBinding next = itsInterfaces[a];
580: for (int b = 0; b < nextPosition; b++)
581: if (next == interfacesToVisit[b])
582: continue nextInterface;
583: interfacesToVisit[nextPosition++] = next;
584: }
585: }
586: }
587: } else {
588: allSuperclassesAreAbstract = false;
589: }
590: }
591:
592: MethodBinding[] methods = super Type.unResolvedMethods();
593: nextMethod: for (int m = methods.length; --m >= 0;) {
594: MethodBinding inheritedMethod = methods[m];
595: if (inheritedMethod.isPrivate()
596: || inheritedMethod.isConstructor()
597: || inheritedMethod.isDefaultAbstract())
598: continue nextMethod;
599: MethodBinding[] existingMethods = (MethodBinding[]) this .inheritedMethods
600: .get(inheritedMethod.selector);
601: if (existingMethods != null) {
602: for (int i = 0, length = existingMethods.length; i < length; i++) {
603: if (existingMethods[i].declaringClass != inheritedMethod.declaringClass
604: && areMethodsCompatible(
605: existingMethods[i],
606: inheritedMethod)) {
607: if (inheritedMethod.isDefault()
608: && inheritedMethod.isAbstract())
609: checkPackagePrivateAbstractMethod(inheritedMethod);
610: continue nextMethod;
611: }
612: }
613: }
614: MethodBinding[] nonVisible = (MethodBinding[]) nonVisibleDefaultMethods
615: .get(inheritedMethod.selector);
616: if (nonVisible != null)
617: for (int i = 0, l = nonVisible.length; i < l; i++)
618: if (areMethodsCompatible(nonVisible[i],
619: inheritedMethod))
620: continue nextMethod;
621:
622: if (!inheritedMethod.isDefault()
623: || inheritedMethod.declaringClass.fPackage == type.fPackage) {
624: if (existingMethods == null) {
625: existingMethods = new MethodBinding[] { inheritedMethod };
626: } else {
627: int length = existingMethods.length;
628: System
629: .arraycopy(
630: existingMethods,
631: 0,
632: existingMethods = new MethodBinding[length + 1],
633: 0, length);
634: existingMethods[length] = inheritedMethod;
635: }
636: this .inheritedMethods.put(inheritedMethod.selector,
637: existingMethods);
638: } else {
639: if (nonVisible == null) {
640: nonVisible = new MethodBinding[] { inheritedMethod };
641: } else {
642: int length = nonVisible.length;
643: System
644: .arraycopy(
645: nonVisible,
646: 0,
647: nonVisible = new MethodBinding[length + 1],
648: 0, length);
649: nonVisible[length] = inheritedMethod;
650: }
651: nonVisibleDefaultMethods.put(
652: inheritedMethod.selector, nonVisible);
653:
654: if (inheritedMethod.isAbstract()
655: && !this .type.isAbstract()) // non visible abstract methods cannot be overridden so the type must be defined abstract
656: problemReporter()
657: .abstractMethodCannotBeOverridden(
658: this .type, inheritedMethod);
659:
660: MethodBinding[] current = (MethodBinding[]) this .currentMethods
661: .get(inheritedMethod.selector);
662: if (current != null) { // non visible methods cannot be overridden so a warning is issued
663: foundMatch: for (int i = 0, length = current.length; i < length; i++) {
664: if (areMethodsCompatible(current[i],
665: inheritedMethod)) {
666: problemReporter()
667: .overridesPackageDefaultMethod(
668: current[i],
669: inheritedMethod);
670: break foundMatch;
671: }
672: }
673: }
674: }
675: }
676: super Type = super Type.super class();
677: }
678: if (nextPosition == 0)
679: return;
680:
681: SimpleSet skip = findSuperinterfaceCollisions(super class,
682: super Interfaces);
683: for (int i = 0; i < nextPosition; i++) {
684: super Type = interfacesToVisit[i];
685: if (super Type.isValidBinding()) {
686: if (skip != null && skip.includes(super Type))
687: continue;
688: if ((itsInterfaces = super Type.super Interfaces()) != Binding.NO_SUPERINTERFACES) {
689: int itsLength = itsInterfaces.length;
690: if (nextPosition + itsLength >= interfacesToVisit.length)
691: System
692: .arraycopy(
693: interfacesToVisit,
694: 0,
695: interfacesToVisit = new ReferenceBinding[nextPosition
696: + itsLength + 5], 0,
697: nextPosition);
698: nextInterface: for (int a = 0; a < itsLength; a++) {
699: ReferenceBinding next = itsInterfaces[a];
700: for (int b = 0; b < nextPosition; b++)
701: if (next == interfacesToVisit[b])
702: continue nextInterface;
703: interfacesToVisit[nextPosition++] = next;
704: }
705: }
706:
707: MethodBinding[] methods = super Type.unResolvedMethods();
708: nextMethod: for (int m = methods.length; --m >= 0;) { // Interface methods are all abstract public
709: MethodBinding inheritedMethod = methods[m];
710: MethodBinding[] existingMethods = (MethodBinding[]) this .inheritedMethods
711: .get(inheritedMethod.selector);
712: if (existingMethods == null) {
713: existingMethods = new MethodBinding[] { inheritedMethod };
714: } else {
715: int length = existingMethods.length;
716: // look to see if any of the existingMethods implement this inheritedMethod
717: for (int e = 0; e < length; e++)
718: if (isInterfaceMethodImplemented(
719: inheritedMethod,
720: existingMethods[e], super Type))
721: continue nextMethod; // skip interface method with the same signature if visible to its declaringClass
722: System
723: .arraycopy(
724: existingMethods,
725: 0,
726: existingMethods = new MethodBinding[length + 1],
727: 0, length);
728: existingMethods[length] = inheritedMethod;
729: }
730: this .inheritedMethods.put(inheritedMethod.selector,
731: existingMethods);
732: }
733: }
734: }
735: }
736:
737: void computeMethods() {
738: MethodBinding[] methods = type.methods();
739: int size = methods.length;
740: this .currentMethods = new HashtableOfObject(size == 0 ? 1
741: : size); // maps method selectors to an array of methods... must search to match paramaters & return type
742: for (int m = size; --m >= 0;) {
743: MethodBinding method = methods[m];
744: if (!(method.isConstructor() || method.isDefaultAbstract())) { // keep all methods which are NOT constructors or default abstract
745: MethodBinding[] existingMethods = (MethodBinding[]) this .currentMethods
746: .get(method.selector);
747: if (existingMethods == null)
748: existingMethods = new MethodBinding[1];
749: else
750: System
751: .arraycopy(
752: existingMethods,
753: 0,
754: (existingMethods = new MethodBinding[existingMethods.length + 1]),
755: 0, existingMethods.length - 1);
756: existingMethods[existingMethods.length - 1] = method;
757: this .currentMethods.put(method.selector,
758: existingMethods);
759: }
760: }
761: }
762:
763: MethodBinding computeSubstituteMethod(
764: MethodBinding inheritedMethod, MethodBinding currentMethod) {
765: if (inheritedMethod == null)
766: return null;
767: if (currentMethod.parameters.length != inheritedMethod.parameters.length)
768: return null; // no match
769: return inheritedMethod;
770: }
771:
772: public boolean doesMethodOverride(MethodBinding method,
773: MethodBinding inheritedMethod) {
774: return areParametersEqual(method, inheritedMethod);
775: }
776:
777: SimpleSet findSuperinterfaceCollisions(ReferenceBinding super class,
778: ReferenceBinding[] super Interfaces) {
779: return null; // noop in 1.4
780: }
781:
782: int[] findOverriddenInheritedMethods(MethodBinding[] methods,
783: int length) {
784: // NOTE assumes length > 1
785: // inherited methods are added as we walk up the superclass hierarchy, then each superinterface
786: // so method[1] from a class can NOT override method[0], but methods from superinterfaces can
787: // since superinterfaces can be added from different superclasses or other superinterfaces
788: int[] toSkip = null;
789: int i = 0;
790: ReferenceBinding declaringClass = methods[i].declaringClass;
791: if (!declaringClass.isInterface()) {
792: // in the first pass, skip overridden methods from superclasses
793: // only keep methods from the closest superclass, all others from higher superclasses can be skipped
794: // NOTE: methods were added in order by walking up the superclass hierarchy
795: ReferenceBinding declaringClass2 = methods[++i].declaringClass;
796: while (declaringClass == declaringClass2) {
797: if (++i == length)
798: return null;
799: declaringClass2 = methods[i].declaringClass;
800: }
801: if (!declaringClass2.isInterface()) {
802: // skip all methods from different superclasses
803: toSkip = new int[length];
804: do {
805: toSkip[i] = -1;
806: if (++i == length)
807: return toSkip;
808: declaringClass2 = methods[i].declaringClass;
809: } while (!declaringClass2.isInterface());
810: }
811: }
812: // in the second pass, skip overridden methods from superinterfaces
813: // NOTE: superinterfaces can appear in 'random' order
814: nextMethod: for (; i < length; i++) {
815: if (toSkip != null && toSkip[i] == -1)
816: continue nextMethod;
817: declaringClass = methods[i].declaringClass;
818: for (int j = i + 1; j < length; j++) {
819: if (toSkip != null && toSkip[j] == -1)
820: continue;
821: ReferenceBinding declaringClass2 = methods[j].declaringClass;
822: if (declaringClass == declaringClass2)
823: continue;
824: if (declaringClass.implements Interface(declaringClass2,
825: true)) {
826: if (toSkip == null)
827: toSkip = new int[length];
828: toSkip[j] = -1;
829: } else if (declaringClass2.implements Interface(
830: declaringClass, true)) {
831: if (toSkip == null)
832: toSkip = new int[length];
833: toSkip[i] = -1;
834: continue nextMethod;
835: }
836: }
837: }
838: return toSkip;
839: }
840:
841: boolean isAsVisible(MethodBinding newMethod,
842: MethodBinding inheritedMethod) {
843: if (inheritedMethod.modifiers == newMethod.modifiers)
844: return true;
845:
846: if (newMethod.isPublic())
847: return true; // Covers everything
848: if (inheritedMethod.isPublic())
849: return false;
850:
851: if (newMethod.isProtected())
852: return true;
853: if (inheritedMethod.isProtected())
854: return false;
855:
856: return !newMethod.isPrivate(); // The inheritedMethod cannot be private since it would not be visible
857: }
858:
859: boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod,
860: MethodBinding existingMethod, ReferenceBinding super Type) {
861: // skip interface method with the same signature if visible to its declaringClass
862: return areParametersEqual(existingMethod, inheritedMethod)
863: && existingMethod.declaringClass.implements Interface(
864: super Type, true);
865: }
866:
867: boolean isSameClassOrSubclassOf(ReferenceBinding testClass,
868: ReferenceBinding super class) {
869: do {
870: if (testClass == super class)
871: return true;
872: } while ((testClass = testClass.super class()) != null);
873: return false;
874: }
875:
876: boolean mustImplementAbstractMethod(ReferenceBinding declaringClass) {
877: // if the type's superclass is an abstract class, then all abstract methods must be implemented
878: // otherwise, skip it if the type's superclass must implement any of the inherited methods
879: ReferenceBinding super class = this .type.super class();
880: if (declaringClass.isClass()) {
881: while (super class.isAbstract()
882: && super class != declaringClass)
883: super class = super class.super class(); // find the first concrete superclass or the abstract declaringClass
884: } else {
885: if (this .type.implements Interface(declaringClass, false)) {
886: if (this .type.isAbstract())
887: return false; // leave it for the subclasses
888: if (!super class.implements Interface(declaringClass,
889: true)) // only if a superclass does not also implement the interface
890: return true;
891: }
892: while (super class.isAbstract()
893: && !super class.implements Interface(declaringClass,
894: false))
895: super class = super class.super class(); // find the first concrete superclass or the superclass which implements the interface
896: }
897: return super class.isAbstract(); // if it is a concrete class then we have already reported problem against it
898: }
899:
900: boolean mustImplementAbstractMethods() {
901: return !this .type.isInterface() && !this .type.isAbstract();
902: }
903:
904: ProblemReporter problemReporter() {
905: return this .type.scope.problemReporter();
906: }
907:
908: ProblemReporter problemReporter(MethodBinding currentMethod) {
909: ProblemReporter reporter = problemReporter();
910: if (currentMethod.declaringClass == type
911: && currentMethod.sourceMethod() != null) // only report against the currentMethod if its implemented by the type
912: reporter.referenceContext = currentMethod.sourceMethod();
913: return reporter;
914: }
915:
916: /**
917: * Return true and report an incompatibleReturnType error if currentMethod's
918: * return type is strictly incompatible with inheritedMethod's, else return
919: * false and report an unchecked conversion warning. Do not call when
920: * areReturnTypesCompatible(currentMethod, inheritedMethod) returns true.
921: * @param currentMethod the (potentially) inheriting method
922: * @param inheritedMethod the inherited method
923: * @return true if currentMethod's return type is strictly incompatible with
924: * inheritedMethod's
925: */
926: boolean reportIncompatibleReturnTypeError(
927: MethodBinding currentMethod, MethodBinding inheritedMethod) {
928: problemReporter(currentMethod).incompatibleReturnType(
929: currentMethod, inheritedMethod);
930: return true;
931: }
932:
933: ReferenceBinding[] resolvedExceptionTypesFor(MethodBinding method) {
934: ReferenceBinding[] exceptions = method.thrownExceptions;
935: if ((method.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
936: return exceptions;
937:
938: if (!(method.declaringClass instanceof BinaryTypeBinding))
939: return Binding.NO_EXCEPTIONS; // safety check
940:
941: for (int i = exceptions.length; --i >= 0;)
942: exceptions[i] = BinaryTypeBinding.resolveType(
943: exceptions[i], this .environment, true);
944: return exceptions;
945: }
946:
947: void verify(SourceTypeBinding someType) {
948: this .type = someType;
949: computeMethods();
950: computeInheritedMethods();
951: checkMethods();
952: }
953:
954: public String toString() {
955: StringBuffer buffer = new StringBuffer(10);
956: buffer.append("MethodVerifier for type: "); //$NON-NLS-1$
957: buffer.append(type.readableName());
958: buffer.append('\n');
959: buffer.append("\t-inherited methods: "); //$NON-NLS-1$
960: buffer.append(this.inheritedMethods);
961: return buffer.toString();
962: }
963: }
|