Source Code Cross Referenced for MethodVerifier.java in  » IDE-Eclipse » jdt » org » eclipse » jdt » internal » compiler » lookup » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » jdt » org.eclipse.jdt.internal.compiler.lookup 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.