intial version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / lookup / MethodVerifier.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
12
13 import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
14 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
15 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
16 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
17 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
18
19 public final class MethodVerifier implements TagBits, TypeConstants {
20         SourceTypeBinding type;
21         HashtableOfObject inheritedMethods;
22         HashtableOfObject currentMethods;
23         ReferenceBinding runtimeException;
24         ReferenceBinding errorException;
25 /*
26 Binding creation is responsible for reporting all problems with types:
27         - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final)
28                 - plus invalid modifiers given the context (the verifier did not do this before)
29         - qualified name collisions between a type and a package (types in default packages are excluded)
30         - all type hierarchy problems:
31                 - cycles in the superclass or superinterface hierarchy
32                 - an ambiguous, invisible or missing superclass or superinterface
33                 - extending a final class
34                 - extending an interface instead of a class
35                 - implementing a class instead of an interface
36                 - implementing the same interface more than once (ie. duplicate interfaces)
37         - with nested types:
38                 - shadowing an enclosing type's source name
39                 - defining a static class or interface inside a non-static nested class
40                 - defining an interface as a local type (local types can only be classes)
41
42 verifyTypeStructure
43
44         | hasHierarchyProblem superclass current names interfaces interfacesByIndentity duplicateExists invalidType |
45
46         (type basicModifiers anyMask: AccModifierProblem | AccAlternateModifierProblem) ifTrue: [
47                 self reportModifierProblemsOnType: type].
48
49         type controller isJavaDefaultPackage ifFalse: [
50                 (nameEnvironment class doesPackageExistNamed: type javaQualifiedName) ifTrue: [
51                         problemSummary
52                                 reportVerificationProblem: #CollidesWithPackage
53                                 args: (Array with: type javaQualifiedName)
54                                 severity: nil
55                                 forType: type]].
56
57         hasHierarchyProblem := false.
58
59         type isJavaClass
60                 ifTrue: [
61                         (superclass := self superclassFor: type) ~~ nil ifTrue: [
62                                 superclass isBuilderClass ifTrue: [
63                                         superclass := superclass newClass].
64                                 superclass isJavaMissing
65                                         ifTrue: [
66                                                 hasHierarchyProblem := true.
67                                                 type javaSuperclassIsMissing ifTrue: [
68                                                         problemSummary
69                                                                 reportVerificationProblem: #MissingSuperclass
70                                                                 args: (Array with: superclass javaQualifiedName with: superclass unmatchedDescriptor)
71                                                                 severity: nil
72                                                                 forType: type].
73                                                 type javaSuperclassCreatesCycle ifTrue: [
74                                                         problemSummary
75                                                                 reportVerificationProblem: #CyclicSuperclass
76                                                                 args: (Array with: superclass javaQualifiedName)
77                                                                 severity: nil
78                                                                 forType: type].
79                                                 type javaSuperclassIsInterface ifTrue: [
80                                                         problemSummary
81                                                                 reportVerificationProblem: #ClassCannotExtendAnInterface
82                                                                 args: (Array with: superclass javaQualifiedName)
83                                                                 severity: nil
84                                                                 forType: type]]
85                                         ifFalse: [
86                                                 "NOTE:  If type is a Java class and its superclass is
87                                                 a valid descriptor then it should NEVER be an interface."
88
89                                                 superclass isJavaFinal ifTrue: [
90                                                         problemSummary
91                                                                 reportVerificationProblem: #ClassCannotExtendFinalClass
92                                                                 args: nil
93                                                                 severity: nil
94                                                                 forType: type]]]]
95                 ifFalse: [
96                         type isJavaLocalType ifTrue: [
97                                 problemSummary
98                                         reportVerificationProblem: #CannotDefineLocalInterface
99                                         args: nil
100                                         severity: nil
101                                         forType: type]].
102
103         type isJavaNestedType ifTrue: [
104                 (current := type) sourceName notEmpty ifTrue: [
105                         names := Set new.
106                         [(current := current enclosingType) ~~ nil] whileTrue: [
107                                 names add: current sourceName].
108
109                         (names includes: type sourceName) ifTrue: [
110                                 problemSummary
111                                         reportVerificationProblem: #NestedTypeCannotShadowTypeName
112                                         args: nil
113                                         severity: nil
114                                         forType: type]].
115
116                 (type enclosingType isJavaNestedType and: [type enclosingType isJavaClass]) ifTrue: [
117                         type enclosingType isJavaStatic ifFalse: [
118                                 type isJavaClass
119                                         ifTrue: [
120                                                 type isJavaStatic ifTrue: [
121                                                         problemSummary
122                                                                 reportVerificationProblem: #StaticClassCannotExistInNestedClass
123                                                                 args: nil
124                                                                 severity: nil
125                                                                 forType: type]]
126                                         ifFalse: [
127                                                 problemSummary
128                                                         reportVerificationProblem: #InterfaceCannotExistInNestedClass
129                                                         args: nil
130                                                         severity: nil
131                                                         forType: type]]]].
132
133         (interfaces := newClass superinterfaces) notEmpty ifTrue: [
134                 interfacesByIndentity := interfaces asSet.
135                 duplicateExists := interfaces size ~~ interfacesByIndentity size.
136
137                 interfacesByIndentity do: [:interface |
138                         duplicateExists ifTrue: [
139                                 (interfaces occurrencesOf: interface) > 1 ifTrue: [
140                                         problemSummary
141                                                 reportVerificationProblem: #InterfaceIsSpecifiedMoreThanOnce
142                                                 args: (Array with: interface javaQualifiedName)
143                                                 severity: nil
144                                                 forType: type]].
145
146                         interface isJavaMissing ifTrue: [
147                                 hasHierarchyProblem := true.
148                                 interface basicClass == JavaInterfaceIsClass basicClass
149                                         ifTrue: [
150                                                 problemSummary
151                                                         reportVerificationProblem: #UsingClassWhereInterfaceIsRequired
152                                                         args: (Array with: interface javaQualifiedName)
153                                                         severity: nil
154                                                         forType: type]
155                                         ifFalse: [
156                                                 interface basicClass == JavaMissingInterface basicClass
157                                                         ifTrue: [
158                                                                 problemSummary
159                                                                         reportVerificationProblem: #MissingInterface
160                                                                         args: (Array with: interface javaQualifiedName with: interface unmatchedDescriptor)
161                                                                         severity: nil
162                                                                         forType: type]
163                                                         ifFalse: [
164                                                                 problemSummary
165                                                                         reportVerificationProblem: #CyclicSuperinterface
166                                                                         args: (Array with: interface javaQualifiedName)
167                                                                         severity: nil
168                                                                         forType: type]]]]].
169
170         hasHierarchyProblem ifFalse: [
171                 "Search up the type's hierarchy for
172                         1. missing superclass,
173                         2. superclass cycle, or
174                         3. superclass is interface."
175                 (invalidType := newClass findFirstInvalidSupertypeSkipping: EsIdentitySet new) ~~ nil ifTrue: [
176                         problemSummary
177                                 reportVerificationProblem: #HasHierarchyProblem
178                                 args: (Array with: invalidType javaReadableName)
179                                 severity: nil
180                                 forType: type]]
181
182 reportModifierProblemsOnType: aType
183
184         (type basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [
185                 (type basicModifiers anyMask: AccModifierProblem)
186                         ifTrue: [
187                                 ^problemSummary
188                                         reportVerificationProblem: #OnlyOneVisibilityModifierAllowed
189                                         args: nil
190                                         severity: nil
191                                         forType: aType]
192                         ifFalse: [
193                                 ^problemSummary
194                                         reportVerificationProblem: #DuplicateModifier
195                                         args: nil
196                                         severity: nil
197                                         forType: aType]].
198
199         type isJavaInterface ifTrue: [
200                 ^problemSummary
201                         reportVerificationProblem: #IllegalModifierForInterface
202                         args: nil
203                         severity: nil
204                         forType: aType].
205
206         (type basicModifiers allMask: AccAbstract | AccFinal) ifTrue: [
207                 ^problemSummary
208                         reportVerificationProblem: #IllegalModifierCombinationAbstractFinal
209                         args: nil
210                         severity: nil
211                         forType: aType].
212
213         ^problemSummary
214                 reportVerificationProblem: #IllegalModifierForClass
215                 args: nil
216                 severity: nil
217                 forType: aType
218
219 void reportModifierProblems() {
220         if (this.type.isAbstract() && this.type.isFinal())
221                 this.problemReporter.illegalModifierCombinationAbstractFinal(this.type);
222
223         // Should be able to detect all 3 problems NOT just 1
224         if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) {
225                 if (this.type.isInterface())
226                         this.problemReporter.illegalModifierForInterface(this.type);
227                 else
228                         this.problemReporter.illegalModifier(this.type);
229         } else {
230                 if ((type.modifiers() & Modifiers.AccModifierProblem) != 0)
231                         this.problemReporter.onlyOneVisibilityModifierAllowed(this.type);
232                 else
233                         this.problemReporter.duplicateModifier(this.type);
234         }
235 }
236 */
237 public MethodVerifier(LookupEnvironment environment) {
238         this.type = null;               // Initialized with the public method verify(SourceTypeBinding)
239         this.inheritedMethods = null;
240         this.currentMethods = null;
241         this.runtimeException = null;
242         this.errorException = null;
243 }
244 private void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length) {
245         for (int i = length; --i >= 0;) {
246                 MethodBinding inheritedMethod = methods[i];
247                 if (currentMethod.returnType != inheritedMethod.returnType) {
248                         this.problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod);
249                 } else if (currentMethod.isStatic() != inheritedMethod.isStatic())       {      // Cannot override a static method or hide an instance method
250                         this.problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod);
251                 } else {
252                         if (currentMethod.thrownExceptions != NoExceptions)
253                                 this.checkExceptions(currentMethod, inheritedMethod);
254                         if (inheritedMethod.isFinal())
255                                 this.problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
256                         if (!this.isAsVisible(currentMethod, inheritedMethod))
257                                 this.problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod);
258                         if (inheritedMethod.isViewedAsDeprecated())
259                                 if (!currentMethod.isViewedAsDeprecated())
260                                         this.problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod);
261                 }
262         }
263 }
264 /*
265 "8.4.4"
266 Verify that newExceptions are all included in inheritedExceptions.
267 Assumes all exceptions are valid and throwable.
268 Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203).
269 */
270
271 private void checkExceptions(MethodBinding newMethod, MethodBinding inheritedMethod) {
272         ReferenceBinding[] newExceptions = newMethod.thrownExceptions;
273         ReferenceBinding[] inheritedExceptions = inheritedMethod.thrownExceptions;
274         for (int i = newExceptions.length; --i >= 0;) {
275                 ReferenceBinding newException = newExceptions[i];
276                 int j = inheritedExceptions.length;
277                 while (--j > -1 && !this.isSameClassOrSubclassOf(newException, inheritedExceptions[j]));
278                 if (j == -1)
279                         if (!(newException.isCompatibleWith(this.runtimeException()) || newException.isCompatibleWith(this.errorException())))
280                                 this.problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException);
281         }
282 }
283 private void checkInheritedMethods(MethodBinding[] methods, int length) {
284         TypeBinding returnType = methods[0].returnType;
285         int index = length;
286         while ((--index > 0) && (returnType == methods[index].returnType));
287         if (index > 0) {                // All inherited methods do NOT have the same vmSignature
288                 this.problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
289                 return;
290         }
291
292         MethodBinding concreteMethod = null;
293         if (!type.isInterface()){ // ignore concrete methods for interfaces
294                 for (int i = length; --i >= 0;)         // Remember that only one of the methods can be non-abstract
295                         if (!methods[i].isAbstract()) {
296                                 concreteMethod = methods[i];
297                                 break;
298                         }
299         }
300         if (concreteMethod == null) {
301                 if (this.type.isClass() && !this.type.isAbstract()) {
302                         for (int i = length; --i >= 0;)
303                                 if (!mustImplementAbstractMethod(methods[i]))
304                                         return;         // in this case, we have already reported problem against the concrete superclass
305
306                                 TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
307                                 if (typeDeclaration != null) {
308                                         MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]);
309                                         missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
310                                 } else {
311                                         this.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
312                                 }
313                 }
314                 return;
315         }
316
317         MethodBinding[] abstractMethods = new MethodBinding[length - 1];
318         index = 0;
319         for (int i = length; --i >= 0;)
320                 if (methods[i] != concreteMethod)
321                         abstractMethods[index++] = methods[i];
322
323         // Remember that interfaces can only define public instance methods
324         if (concreteMethod.isStatic())
325                 // Cannot inherit a static method which is specified as an instance method by an interface
326                 this.problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods);   
327         if (!concreteMethod.isPublic())
328                 // Cannot reduce visibility of a public method specified by an interface
329                 this.problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
330         if (concreteMethod.thrownExceptions != NoExceptions)
331                 for (int i = abstractMethods.length; --i >= 0;)
332                         this.checkExceptions(concreteMethod, abstractMethods[i]);
333 }
334 /*
335 For each inherited method identifier (message pattern - vm signature minus the return type)
336         if current method exists
337                 if current's vm signature does not match an inherited signature then complain 
338                 else compare current's exceptions & visibility against each inherited method
339         else
340                 if inherited methods = 1
341                         if inherited is abstract && type is NOT an interface or abstract, complain
342                 else
343                         if vm signatures do not match complain
344                         else
345                                 find the concrete implementation amongst the abstract methods (can only be 1)
346                                 if one exists then
347                                         it must be a public instance method
348                                         compare concrete's exceptions against each abstract method
349                                 else
350                                         complain about missing implementation only if type is NOT an interface or abstract
351 */
352
353 private void checkMethods() {
354         boolean mustImplementAbstractMethods = this.type.isClass() && !this.type.isAbstract();
355         char[][] methodSelectors = this.inheritedMethods.keyTable;
356         for (int s = methodSelectors.length; --s >= 0;) {
357                 if (methodSelectors[s] != null) {
358                         MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]);
359                         MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s];
360
361                         int index = -1;
362                         MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
363                         if (current != null) {
364                                 for (int i = 0, length1 = current.length; i < length1; i++) {
365                                         while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
366                                         MethodBinding currentMethod = current[i];
367                                         for (int j = 0, length2 = inherited.length; j < length2; j++) {
368                                                 if (inherited[j] != null && currentMethod.areParametersEqual(inherited[j])) {
369                                                         matchingInherited[++index] = inherited[j];
370                                                         inherited[j] = null; // do not want to find it again
371                                                 }
372                                         }
373                                         if (index >= 0)
374                                                 this.checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching
375                                 }
376                         }
377                         for (int i = 0, length = inherited.length; i < length; i++) {
378                                 while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
379                                 if (inherited[i] != null) {
380                                         matchingInherited[++index] = inherited[i];
381                                         for (int j = i + 1; j < length; j++) {
382                                                 if (inherited[j] != null && inherited[i].areParametersEqual(inherited[j])) {
383                                                         matchingInherited[++index] = inherited[j];
384                                                         inherited[j] = null; // do not want to find it again
385                                                 }
386                                         }
387                                 }
388                                 if (index > 0) {
389                                         this.checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
390                                 } else {
391                                         if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract())
392                                                 if (mustImplementAbstractMethod(matchingInherited[0])) {
393                                                         TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
394                                                         if (typeDeclaration != null) {
395                                                                 MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(matchingInherited[0]);
396                                                                 missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, matchingInherited[0]);
397                                                         } else {
398                                                                 this.problemReporter().abstractMethodMustBeImplemented(this.type, matchingInherited[0]);
399                                                         }
400                                                 }
401                                 }
402                         }
403                 }
404         }
405 }
406 /*
407 Binding creation is responsible for reporting:
408         - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations)
409                 - plus invalid modifiers given the context... examples:
410                         - interface methods can only be public
411                         - abstract methods can only be defined by abstract classes
412         - collisions... 2 methods with identical vmSelectors
413         - multiple methods with the same message pattern but different return types
414         - ambiguous, invisible or missing return/argument/exception types
415         - check the type of any array is not void
416         - check that each exception type is Throwable or a subclass of it
417 */
418 private void computeInheritedMethods() {
419         this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type
420         ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
421         int lastPosition = 0;
422         interfacesToVisit[lastPosition] = type.superInterfaces();
423
424         ReferenceBinding superType;
425         if (this.type.isClass()) {
426                 superType = this.type.superclass();
427         } else { // check interface methods against Object
428                 superType = this.type.scope.getJavaLangObject();
429         }
430         MethodBinding[] nonVisibleDefaultMethods = null;
431         int nonVisibleCount = 0;
432
433         while (superType != null) {
434                 if (superType.isValidBinding()) {
435                         ReferenceBinding[] itsInterfaces = superType.superInterfaces();
436                         if (itsInterfaces != NoSuperInterfaces) {
437                                 if (++lastPosition == interfacesToVisit.length)
438                                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
439                                 interfacesToVisit[lastPosition] = itsInterfaces;
440                         }
441
442                         MethodBinding[] methods = superType.methods();
443                         nextMethod : for (int m = methods.length; --m >= 0;) {
444                                 MethodBinding method = methods[m];
445                                 if (!(method.isPrivate() || method.isConstructor() || method.isDefaultAbstract())) { // look at all methods which are NOT private or constructors or default abstract
446                                         MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector);
447                                         if (existingMethods != null)
448                                                 for (int i = 0, length = existingMethods.length; i < length; i++)
449                                                         if (method.returnType == existingMethods[i].returnType)
450                                                                 if (method.areParametersEqual(existingMethods[i]))
451                                                                         continue nextMethod;
452                                         if (nonVisibleDefaultMethods != null)
453                                                 for (int i = 0; i < nonVisibleCount; i++)
454                                                         if (method.returnType == nonVisibleDefaultMethods[i].returnType)
455                                                                 if (CharOperation.equals(method.selector, nonVisibleDefaultMethods[i].selector))
456                                                                         if (method.areParametersEqual(nonVisibleDefaultMethods[i]))
457                                                                                 continue nextMethod;
458
459                                         if (!(method.isDefault() && (method.declaringClass.fPackage != type.fPackage))) { // ignore methods which have default visibility and are NOT defined in another package
460                                                 if (existingMethods == null)
461                                                         existingMethods = new MethodBinding[1];
462                                                 else
463                                                         System.arraycopy(existingMethods, 0,
464                                                                 (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1);
465                                                 existingMethods[existingMethods.length - 1] = method;
466                                                 this.inheritedMethods.put(method.selector, existingMethods);
467                                         } else {
468                                                 if (nonVisibleDefaultMethods == null)
469                                                         nonVisibleDefaultMethods = new MethodBinding[10];
470                                                 else if (nonVisibleCount == nonVisibleDefaultMethods.length)
471                                                         System.arraycopy(nonVisibleDefaultMethods, 0,
472                                                                 (nonVisibleDefaultMethods = new MethodBinding[nonVisibleCount * 2]), 0, nonVisibleCount);
473                                                 nonVisibleDefaultMethods[nonVisibleCount++] = method;
474
475                                                 if (method.isAbstract() && !this.type.isAbstract()) // non visible abstract methods cannot be overridden so the type must be defined abstract
476                                                         this.problemReporter().abstractMethodCannotBeOverridden(this.type, method);
477
478                                                 MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(method.selector);
479                                                 if (current != null) { // non visible methods cannot be overridden so a warning is issued
480                                                         foundMatch : for (int i = 0, length = current.length; i < length; i++) {
481                                                                 if (method.returnType == current[i].returnType) {
482                                                                         if (method.areParametersEqual(current[i])) {
483                                                                                 this.problemReporter().overridesPackageDefaultMethod(current[i], method);
484                                                                                 break foundMatch;
485                                                                         }
486                                                                 }
487                                                         }
488                                                 }
489                                         }
490                                 }
491                         }
492                         superType = superType.superclass();
493                 }
494         }
495
496         for (int i = 0; i <= lastPosition; i++) {
497                 ReferenceBinding[] interfaces = interfacesToVisit[i];
498                 for (int j = 0, length = interfaces.length; j < length; j++) {
499                         superType = interfaces[j];
500                         if ((superType.tagBits & InterfaceVisited) == 0) {
501                                 superType.tagBits |= InterfaceVisited;
502                                 if (superType.isValidBinding()) {
503                                         ReferenceBinding[] itsInterfaces = superType.superInterfaces();
504                                         if (itsInterfaces != NoSuperInterfaces) {
505                                                 if (++lastPosition == interfacesToVisit.length)
506                                                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
507                                                 interfacesToVisit[lastPosition] = itsInterfaces;
508                                         }
509
510                                         MethodBinding[] methods = superType.methods();
511                                         for (int m = methods.length; --m >= 0;) { // Interface methods are all abstract public
512                                                 MethodBinding method = methods[m];
513                                                 MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(method.selector);
514                                                 if (existingMethods == null)
515                                                         existingMethods = new MethodBinding[1];
516                                                 else
517                                                         System.arraycopy(existingMethods, 0,
518                                                                 (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1);
519                                                 existingMethods[existingMethods.length - 1] = method;
520                                                 this.inheritedMethods.put(method.selector, existingMethods);
521                                         }
522                                 }
523                         }
524                 }
525         }
526
527         // bit reinitialization
528         for (int i = 0; i <= lastPosition; i++) {
529                 ReferenceBinding[] interfaces = interfacesToVisit[i];
530                 for (int j = 0, length = interfaces.length; j < length; j++)
531                         interfaces[j].tagBits &= ~InterfaceVisited;
532         }
533 }
534 /*
535 computeInheritedMethodMembers
536
537         "8.4.6.4"
538         "Compute all of the members for the type that are inherited from its supertypes.
539                 This includes:
540                         All of the methods implemented in the supertype hierarchy that are not overridden.
541                         PROBLEM:  Currently we do not remove overridden methods in the interface hierarchy.
542                         This could cause a non-existent exception error to be detected."
543
544         | supertype allSuperinterfaces methodsSeen interfacesSeen |
545         inheritedMethodMembers := LookupTable new: 50.
546         allSuperinterfaces := OrderedCollection new.
547
548         type isJavaClass ifTrue: [
549                 supertype := type.
550                 methodsSeen := EsIdentitySet new: 20.
551                 [(supertype := self superclassFor: supertype) == nil] whileFalse: [
552                         (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [
553                                 allSuperinterfaces addAll: (self superinterfacesFor: supertype).
554                                 supertype javaUserDefinedMethodsDo: [:method |
555                                         (method isJavaPrivate or: [method isJavaConstructor]) ifFalse: [
556                                                 (method isJavaDefault and: [method declaringClass package symbol ~= type package symbol]) ifFalse: [
557                                                         (methodsSeen includes: method selector) ifFalse: [
558                                                                 methodsSeen add: method selector.
559                                                                 (inheritedMethodMembers
560                                                                         at: (self methodSignatureFor: method selector)
561                                                                         ifAbsentPut: [OrderedCollection new: 3])
562                                                                                 add: method]]]]]]].
563
564         allSuperinterfaces addAll: (self superinterfacesFor: type).
565         interfacesSeen := EsIdentitySet new: allSuperinterfaces size * 2.
566         [allSuperinterfaces notEmpty] whileTrue: [
567                 supertype := allSuperinterfaces removeFirst.
568                 (interfacesSeen includes: supertype) ifFalse: [
569                         interfacesSeen add: supertype.
570                         (supertype isBuilderClass or: [supertype isValidDescriptor]) ifTrue: [
571                                 allSuperinterfaces addAll: (self superinterfacesFor: supertype).
572                                 supertype javaUserDefinedMethodsDo: [:method |          "Interface methods are all abstract public."
573                                         (inheritedMethodMembers
574                                                 at: (self methodSignatureFor: method selector)
575                                                 ifAbsentPut: [OrderedCollection new: 3])
576                                                         add: method]]]]
577 */
578 private void computeMethods() {
579         MethodBinding[] methods = type.methods();
580         int size = methods.length;
581         this.currentMethods = new HashtableOfObject(size == 0 ? 1 : size); // maps method selectors to an array of methods... must search to match paramaters & return type
582         for (int m = size; --m >= 0;) {
583                 MethodBinding method = methods[m];
584                 if (!(method.isConstructor() || method.isDefaultAbstract())) { // keep all methods which are NOT constructors or default abstract
585                         MethodBinding[] existingMethods = (MethodBinding[]) this.currentMethods.get(method.selector);
586                         if (existingMethods == null)
587                                 existingMethods = new MethodBinding[1];
588                         else
589                                 System.arraycopy(existingMethods, 0,
590                                         (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1);
591                         existingMethods[existingMethods.length - 1] = method;
592                         this.currentMethods.put(method.selector, existingMethods);
593                 }
594         }
595 }
596 private ReferenceBinding errorException() {
597         if (errorException == null)
598                 this.errorException = this.type.scope.getJavaLangError();
599         return errorException;
600 }
601 private boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
602         if (inheritedMethod.modifiers == newMethod.modifiers) return true;
603
604         if (newMethod.isPublic()) return true;          // Covers everything
605         if (inheritedMethod.isPublic()) return false;
606
607         if (newMethod.isProtected()) return true;
608         if (inheritedMethod.isProtected()) return false;
609
610         return !newMethod.isPrivate();          // The inheritedMethod cannot be private since it would not be visible
611 }
612 private boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) {
613         do {
614                 if (testClass == superclass) return true;
615         } while ((testClass = testClass.superclass()) != null);
616         return false;
617 }
618 private boolean mustImplementAbstractMethod(MethodBinding abstractMethod) {
619         // if the type's superclass is an abstract class, then all abstract methods must be implemented
620         // otherwise, skip it if the type's superclass must implement any of the inherited methods
621         ReferenceBinding superclass = this.type.superclass();
622         ReferenceBinding declaringClass = abstractMethod.declaringClass;
623         if (declaringClass.isClass()) {
624                 while (superclass.isAbstract() && superclass != declaringClass)
625                         superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass
626         } else {
627                 if (this.type.implementsInterface(declaringClass, false))
628                         return !this.type.isAbstract();
629                 while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false))
630                         superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface
631         }
632         return superclass.isAbstract();         // if it is a concrete class then we have already reported problem against it
633 }
634 private ProblemReporter problemReporter() {
635         return this.type.scope.problemReporter();
636 }
637 private ProblemReporter problemReporter(MethodBinding currentMethod) {
638         ProblemReporter reporter = problemReporter();
639         if (currentMethod.declaringClass == type)       // only report against the currentMethod if its implemented by the type
640                 reporter.referenceContext = currentMethod.sourceMethod();
641         return reporter;
642 }
643 private ReferenceBinding runtimeException() {
644         if (runtimeException == null)
645                 this.runtimeException = this.type.scope.getJavaLangRuntimeException();
646         return runtimeException;
647 }
648 public void verify(SourceTypeBinding type) {
649         this.type = type;
650         this.computeMethods();
651         this.computeInheritedMethods();
652         this.checkMethods();
653 }
654 private void zzFieldProblems() {
655 }
656 /*
657 Binding creation is responsible for reporting all problems with fields:
658         - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - final/volatile)
659                 - plus invalid modifiers given the context (the verifier did not do this before)
660                 - include initializers in the modifier checks even though bindings are not created
661         - collisions... 2 fields with same name
662         - interfaces cannot define initializers
663         - nested types cannot define static fields
664         - with the type of the field:
665                 - void is not a valid type (or for an array)
666                 - an ambiguous, invisible or missing type
667
668 verifyFields
669
670         | toSearch |
671         (toSearch := newClass fields) notEmpty ifTrue: [
672                 newClass fromJavaClassFile
673                         ifTrue: [
674                                 toSearch do: [:field |
675                                         field isJavaInitializer ifFalse: [
676                                                 self verifyFieldType: field]]]
677                         ifFalse: [
678                                 toSearch do: [:field |
679                                         field isJavaInitializer
680                                                 ifTrue: [self verifyFieldInitializer: field]
681                                                 ifFalse: [self verifyField: field]]]]
682
683 verifyFieldInitializer: field
684
685         type isJavaInterface
686                 ifTrue: [
687                         problemSummary
688                                 reportVerificationProblem: #InterfacesCannotHaveInitializers
689                                 args: #()
690                                 severity: nil
691                                 forField: field]
692                 ifFalse: [
693                         field isJavaStatic
694                                 ifTrue: [
695                                         field modifiers == AccStatic ifFalse: [
696                                                 problemSummary
697                                                         reportVerificationProblem: #IllegalModifierForStaticInitializer
698                                                         args: #()
699                                                         severity: nil
700                                                         forField: field]]
701                                 ifFalse: [
702                                         field modifiers == 0 ifFalse: [
703                                                 problemSummary
704                                                         reportVerificationProblem: #IllegalModifierForInitializer
705                                                         args: #()
706                                                         severity: nil
707                                                         forField: field]]]
708
709 verifyField: field
710
711         (field basicModifiers anyMask: AccAlternateModifierProblem | AccModifierProblem) ifTrue: [
712                 self reportModifierProblemsOnField: field].
713
714         field isJavaStatic ifTrue: [
715                 type isJavaStatic ifFalse: [
716                         (type isJavaNestedType and: [type isJavaClass]) ifTrue: [
717                                 problemSummary
718                                         reportVerificationProblem: #NestedClassCannotHaveStaticField
719                                         args: #()
720                                         severity: nil
721                                         forField: field]]].
722
723         self verifyFieldType: field
724
725 verifyFieldType: field
726
727         | descriptor fieldType |
728         "8.3 (Class) 9.3 (Interface)"
729         "Optimize the base type case"
730         field typeIsBaseType
731                 ifTrue: [
732                         field typeName = 'V' ifTrue: [  "$NON-NLS$"
733                                 problemSummary
734                                         reportVerificationProblem: #IllegalTypeForField
735                                         args: (Array with: JavaVoid)
736                                         severity: nil
737                                         forField: field]]
738                 ifFalse: [
739                         descriptor := field asDescriptorIn: nameEnvironment.
740                         (fieldType := descriptor type) isValidDescriptor
741                                 ifTrue: [
742                                         (fieldType isArrayType and: [fieldType leafComponentType isVoidType]) ifTrue: [
743                                                 problemSummary
744                                                         reportVerificationProblem: #InvalidArrayType
745                                                         args: (Array with: fieldType javaReadableName)
746                                                         severity: nil
747                                                         forField: field]]
748                                 ifFalse: [
749                                         problemSummary
750                                                 reportVerificationProblem: #UnboundTypeForField
751                                                 args: (Array with: fieldType javaReadableName with: fieldType leafComponentType)
752                                                 severity: nil
753                                                 forField: field]].
754
755 reportModifierProblemsOnField: field
756
757         (field basicModifiers anyMask: AccAlternateModifierProblem) ifTrue: [
758                 (field basicModifiers anyMask: AccModifierProblem)
759                         ifTrue: [
760                                 ^problemSummary
761                                         reportVerificationProblem: #OnlyOneVisibilityModifierAllowed
762                                         args: #()
763                                         severity: ErrorInfo::ConflictingModifier
764                                         forField: field]
765                         ifFalse: [
766                                 ^problemSummary
767                                         reportVerificationProblem: #DuplicateModifier
768                                         args: #()
769                                         severity: ErrorInfo::ConflictingModifier
770                                         forField: field]].
771
772         type isJavaInterface ifTrue: [
773                 ^problemSummary
774                         reportVerificationProblem: #IllegalModifierForInterfaceField
775                         args: #()
776                         severity: nil
777                         forField: field].
778
779         (field basicModifiers allMask: AccFinal |  AccVolatile) ifTrue: [
780                 ^problemSummary
781                         reportVerificationProblem: #IllegalModifierCombinationFinalVolatile
782                         args: #()
783                         severity: nil
784                         forField: field].
785
786         ^problemSummary
787                 reportVerificationProblem: #IllegalModifierForField
788                 args: #()
789                 severity: nil
790                 forField: field
791
792 void reportModifierProblems(FieldBinding field) {
793         if (field.isFinal() && field.isVolatile())
794                 this.problemReporter.illegalModifierCombinationFinalVolatile(field);
795
796         // Should be able to detect all 3 problems NOT just 1
797         if ((type.modifiers() & Modifiers.AccAlternateModifierProblem) == 0) {
798                 if (this.type.isInterface())
799                         this.problemReporter.illegalModifierForInterfaceField(field);
800                 else
801                         this.problemReporter.illegalModifier(field);
802         } else {
803                 if ((field.modifiers & Modifiers.AccModifierProblem) != 0)
804                         this.problemReporter.onlyOneVisibilityModifierAllowed(field);
805                 else
806                         this.problemReporter.duplicateModifier(field);
807         }
808 }
809 */
810 private void zzImportProblems() {
811 }
812 /*
813 Binding creation is responsible for reporting all problems with imports:
814         - on demand imports which refer to missing packages
815         - with single type imports:
816                 - resolves to an ambiguous, invisible or missing type
817                 - conflicts with the type's source name
818                 - has the same simple name as another import
819
820 Note: VAJ ignored duplicate imports (only one was kept)
821
822 verifyImports
823
824         | importsBySimpleName nameEnvClass imports cl first |
825         importsBySimpleName := LookupTable new.
826         nameEnvClass := nameEnvironment class.
827
828         "7.5.2"
829         type imports do: [:import |
830                 import isOnDemand
831                         ifTrue: [
832                                 (nameEnvClass doesPackageExistNamed: import javaPackageName) ifFalse: [
833                                         (nameEnvClass findJavaClassNamedFrom: import javaPackageName) == nil ifTrue: [
834                                                 problemSummary
835                                                         reportVerificationProblem: #OnDemandImportRefersToMissingPackage
836                                                         args: (Array with: import asString)
837                                                         severity: ErrorInfo::ImportVerification
838                                                         forType: type]]]
839                         ifFalse: [
840                                 (imports := importsBySimpleName at: import javaSimpleName ifAbsent: []) == nil
841                                         ifTrue: [
842                                                 importsBySimpleName at: import javaSimpleName put: (Array with: import)]
843                                         ifFalse: [
844                                                 (imports includes: import) ifFalse: [
845                                                         importsBySimpleName at: import javaSimpleName put: imports, (Array with: import)]].
846
847                                 "Ignore any imports which are simple names - we will treat these as no-ops."
848
849                                 import javaPackageName notEmpty ifTrue: [
850                                         cl := nameEnvClass findJavaClassNamedFrom: import asString.
851
852                                         (cl ~~ nil and: [cl isJavaPublic or: [cl controller symbol == type controller symbol]]) ifFalse: [
853                                                 problemSummary
854                                                         reportVerificationProblem: #SingleTypeImportRefersToInvisibleType
855                                                         args: (Array with: import asString)
856                                                         severity: ErrorInfo::ImportVerification
857                                                         forType: type]]]].
858
859         importsBySimpleName notEmpty ifTrue: [
860                 importsBySimpleName keysAndValuesDo: [:simpleName :matching |
861                         matching size == 1
862                                 ifTrue: [
863                                         simpleName = type sourceName ifTrue: [
864                                                 matching first javaReadableName = type javaReadableName ifFalse: [
865                                                         problemSummary
866                                                                 reportVerificationProblem: #SingleTypeImportConflictsWithType
867                                                                 args: #()
868                                                                 severity: nil
869                                                                 forType: type]]]
870                                 ifFalse: [
871                                         problemSummary
872                                                 reportVerificationProblem: #SingleTypeImportsHaveSameSimpleName
873                                                 args: (Array with: simpleName)
874                                                 severity: nil
875                                                 forType: type]]]
876 */
877 private void zzTypeProblems() {
878 }
879 }