A variable description (like PHPFunctionDeclaration)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / lookup / ClassScope.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.AbstractMethodDeclaration;
14 import net.sourceforge.phpdt.internal.compiler.ast.Clinit;
15 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
16 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
17 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
18 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
19 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
20 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
21 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
22
23 public class ClassScope extends Scope {
24         public TypeDeclaration referenceContext;
25         
26         public ClassScope(Scope parent, TypeDeclaration context) {
27                 super(CLASS_SCOPE, parent);
28                 this.referenceContext = context;
29         }
30         
31         void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) {
32                 
33                 LocalTypeBinding anonymousType = buildLocalType(enclosingType, enclosingType.fPackage);
34
35                 SourceTypeBinding sourceType = referenceContext.binding;
36                 if (supertype.isInterface()) {
37                         sourceType.superclass = getJavaLangObject();
38                         sourceType.superInterfaces = new ReferenceBinding[] { supertype };
39                 } else {
40                         sourceType.superclass = supertype;
41                         sourceType.superInterfaces = TypeBinding.NoSuperInterfaces;
42                 }
43                 connectMemberTypes();
44                 buildFieldsAndMethods();
45                 anonymousType.faultInTypesForFieldsAndMethods();
46                 sourceType.verifyMethods(environment().methodVerifier());
47         }
48         
49         private void buildFields() {
50                 if (referenceContext.fields == null) {
51                         referenceContext.binding.fields = NoFields;
52                         return;
53                 }
54                 // count the number of fields vs. initializers
55                 FieldDeclaration[] fields = referenceContext.fields;
56                 int size = fields.length;
57                 int count = 0;
58                 for (int i = 0; i < size; i++)
59                         if (fields[i].isField())
60                                 count++;
61
62                 // iterate the field declarations to create the bindings, lose all duplicates
63                 FieldBinding[] fieldBindings = new FieldBinding[count];
64                 HashtableOfObject knownFieldNames = new HashtableOfObject(count);
65                 boolean duplicate = false;
66                 count = 0;
67                 for (int i = 0; i < size; i++) {
68                         FieldDeclaration field = fields[i];
69                         if (!field.isField()) {
70                                 if (referenceContext.binding.isInterface())
71                                         problemReporter().interfaceCannotHaveInitializers(referenceContext.binding, field);
72                         } else {
73                                 FieldBinding fieldBinding = new FieldBinding(field, null, referenceContext.binding);
74                                 // field's type will be resolved when needed for top level types
75                                 checkAndSetModifiersForField(fieldBinding, field);
76
77                                 if (knownFieldNames.containsKey(field.name)) {
78                                         duplicate = true;
79                                         FieldBinding previousBinding = (FieldBinding) knownFieldNames.get(field.name);
80                                         if (previousBinding != null) {
81                                                 for (int f = 0; f < i; f++) {
82                                                         FieldDeclaration previousField = fields[f];
83                                                         if (previousField.binding == previousBinding) {
84                                                                 problemReporter().duplicateFieldInType(referenceContext.binding, previousField);
85                                                                 previousField.binding = null;
86                                                                 break;
87                                                         }
88                                                 }
89                                         }
90                                         knownFieldNames.put(field.name, null); // ensure that the duplicate field is found & removed
91                                         problemReporter().duplicateFieldInType(referenceContext.binding, field);
92                                         field.binding = null;
93                                 } else {
94                                         knownFieldNames.put(field.name, fieldBinding);
95                                         // remember that we have seen a field with this name
96                                         if (fieldBinding != null)
97                                                 fieldBindings[count++] = fieldBinding;
98                                 }
99                         }
100                 }
101                 // remove duplicate fields
102                 if (duplicate) {
103                         FieldBinding[] newFieldBindings = new FieldBinding[knownFieldNames.size() - 1];
104                         // we know we'll be removing at least 1 duplicate name
105                         size = count;
106                         count = 0;
107                         for (int i = 0; i < size; i++) {
108                                 FieldBinding fieldBinding = fieldBindings[i];
109                                 if (knownFieldNames.get(fieldBinding.name) != null)
110                                         newFieldBindings[count++] = fieldBinding;
111                         }
112                         fieldBindings = newFieldBindings;
113                 }
114
115                 if (count != fieldBindings.length)
116                         System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count);
117                 for (int i = 0; i < count; i++)
118                         fieldBindings[i].id = i;
119                 referenceContext.binding.fields = fieldBindings;
120         }
121         
122         void buildFieldsAndMethods() {
123                 buildFields();
124                 buildMethods();
125
126                 SourceTypeBinding sourceType = referenceContext.binding;
127                 if (sourceType.isMemberType() && !sourceType.isLocalType())
128                          ((MemberTypeBinding) sourceType).checkSyntheticArgsAndFields();
129
130                 ReferenceBinding[] memberTypes = sourceType.memberTypes;
131                 for (int i = 0, length = memberTypes.length; i < length; i++)
132                          ((SourceTypeBinding) memberTypes[i]).scope.buildFieldsAndMethods();
133         }
134         
135         private LocalTypeBinding buildLocalType(
136                 SourceTypeBinding enclosingType,
137                 PackageBinding packageBinding) {
138                 referenceContext.scope = this;
139                 referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true);
140                 referenceContext.initializerScope = new MethodScope(this, referenceContext, false);
141
142                 // build the binding or the local type
143                 LocalTypeBinding localType = new LocalTypeBinding(this, enclosingType);
144                 referenceContext.binding = localType;
145                 checkAndSetModifiers();
146
147                 // Look at member types
148                 ReferenceBinding[] memberTypeBindings = NoMemberTypes;
149                 if (referenceContext.memberTypes != null) {
150                         int size = referenceContext.memberTypes.length;
151                         memberTypeBindings = new ReferenceBinding[size];
152                         int count = 0;
153                         nextMember : for (int i = 0; i < size; i++) {
154                                 TypeDeclaration memberContext = referenceContext.memberTypes[i];
155                                 if (memberContext.isInterface()) {
156                                         problemReporter().nestedClassCannotDeclareInterface(memberContext);
157                                         continue nextMember;
158                                 }
159                                 ReferenceBinding type = localType;
160                                 // check that the member does not conflict with an enclosing type
161                                 do {
162                                         if (CharOperation.equals(type.sourceName, memberContext.name)) {
163                                                 problemReporter().hidingEnclosingType(memberContext);
164                                                 continue nextMember;
165                                         }
166                                         type = type.enclosingType();
167                                 } while (type != null);
168                                 // check the member type does not conflict with another sibling member type
169                                 for (int j = 0; j < i; j++) {
170                                         if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) {
171                                                 problemReporter().duplicateNestedType(memberContext);
172                                                 continue nextMember;
173                                         }
174                                 }
175
176                                 ClassScope memberScope = new ClassScope(this, referenceContext.memberTypes[i]);
177                                 LocalTypeBinding memberBinding = memberScope.buildLocalType(localType, packageBinding);
178                                 memberBinding.setAsMemberType();
179                                 memberTypeBindings[count++] = memberBinding;
180                         }
181                         if (count != size)
182                                 System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count);
183                 }
184                 localType.memberTypes = memberTypeBindings;
185                 return localType;
186         }
187         
188         void buildLocalTypeBinding(SourceTypeBinding enclosingType) {
189
190                 LocalTypeBinding localType = buildLocalType(enclosingType, enclosingType.fPackage);
191                 connectTypeHierarchy();
192                 buildFieldsAndMethods();
193                 localType.faultInTypesForFieldsAndMethods();
194
195                 referenceContext.binding.verifyMethods(environment().methodVerifier());
196         }
197         
198         private void buildMethods() {
199                 if (referenceContext.methods == null) {
200                         referenceContext.binding.methods = NoMethods;
201                         return;
202                 }
203
204                 // iterate the method declarations to create the bindings
205                 AbstractMethodDeclaration[] methods = referenceContext.methods;
206                 int size = methods.length;
207                 int clinitIndex = -1;
208                 for (int i = 0; i < size; i++) {
209                         if (methods[i] instanceof Clinit) {
210                                 clinitIndex = i;
211                                 break;
212                         }
213                 }
214                 MethodBinding[] methodBindings = new MethodBinding[clinitIndex == -1 ? size : size - 1];
215
216                 int count = 0;
217                 for (int i = 0; i < size; i++) {
218                         if (i != clinitIndex) {
219                                 MethodScope scope = new MethodScope(this, methods[i], false);
220                                 MethodBinding methodBinding = scope.createMethod(methods[i]);
221                                 if (methodBinding != null) // is null if binding could not be created
222                                         methodBindings[count++] = methodBinding;
223                         }
224                 }
225                 if (count != methodBindings.length)
226                         System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[count], 0, count);
227
228                 referenceContext.binding.methods = methodBindings;
229                 referenceContext.binding.modifiers |= AccUnresolved; // until methods() is sent
230         }
231         SourceTypeBinding buildType(SourceTypeBinding enclosingType, PackageBinding packageBinding) {
232                 // provide the typeDeclaration with needed scopes
233                 referenceContext.scope = this;
234                 referenceContext.staticInitializerScope = new MethodScope(this, referenceContext, true);
235                 referenceContext.initializerScope = new MethodScope(this, referenceContext, false);
236
237                 if (enclosingType == null) {
238                         char[][] className = CharOperation.arrayConcat(packageBinding.compoundName, referenceContext.name);
239                         referenceContext.binding = new SourceTypeBinding(className, packageBinding, this);
240                 } else {
241                         char[][] className = CharOperation.deepCopy(enclosingType.compoundName);
242                         className[className.length - 1] =
243                                 CharOperation.concat(className[className.length - 1], referenceContext.name, '$');
244                         referenceContext.binding = new MemberTypeBinding(className, this, enclosingType);
245                 }
246
247                 SourceTypeBinding sourceType = referenceContext.binding;
248                 sourceType.fPackage.addType(sourceType);
249                 checkAndSetModifiers();
250
251                 // Look at member types
252                 ReferenceBinding[] memberTypeBindings = NoMemberTypes;
253                 if (referenceContext.memberTypes != null) {
254                         int size = referenceContext.memberTypes.length;
255                         memberTypeBindings = new ReferenceBinding[size];
256                         int count = 0;
257                         nextMember : for (int i = 0; i < size; i++) {
258                                 TypeDeclaration memberContext = referenceContext.memberTypes[i];
259                                 if (memberContext.isInterface()
260                                         && sourceType.isNestedType()
261                                         && sourceType.isClass()
262                                         && !sourceType.isStatic()) {
263                                         problemReporter().nestedClassCannotDeclareInterface(memberContext);
264                                         continue nextMember;
265                                 }
266                                 ReferenceBinding type = sourceType;
267                                 // check that the member does not conflict with an enclosing type
268                                 do {
269                                         if (CharOperation.equals(type.sourceName, memberContext.name)) {
270                                                 problemReporter().hidingEnclosingType(memberContext);
271                                                 continue nextMember;
272                                         }
273                                         type = type.enclosingType();
274                                 } while (type != null);
275                                 // check that the member type does not conflict with another sibling member type
276                                 for (int j = 0; j < i; j++) {
277                                         if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) {
278                                                 problemReporter().duplicateNestedType(memberContext);
279                                                 continue nextMember;
280                                         }
281                                 }
282
283                                 ClassScope memberScope = new ClassScope(this, memberContext);
284                                 memberTypeBindings[count++] = memberScope.buildType(sourceType, packageBinding);
285                         }
286                         if (count != size)
287                                 System.arraycopy(memberTypeBindings, 0, memberTypeBindings = new ReferenceBinding[count], 0, count);
288                 }
289                 sourceType.memberTypes = memberTypeBindings;
290                 return sourceType;
291         }
292         
293         private void checkAndSetModifiers() {
294                 SourceTypeBinding sourceType = referenceContext.binding;
295                 int modifiers = sourceType.modifiers;
296                 if ((modifiers & AccAlternateModifierProblem) != 0)
297                         problemReporter().duplicateModifierForType(sourceType);
298
299                 ReferenceBinding enclosingType = sourceType.enclosingType();
300                 boolean isMemberType = sourceType.isMemberType();
301                 
302                 if (isMemberType) {
303                         // checks for member types before local types to catch local members
304                         if (enclosingType.isStrictfp())
305                                 modifiers |= AccStrictfp;
306                         if (enclosingType.isDeprecated())
307                                 modifiers |= AccDeprecatedImplicitly;
308                         if (enclosingType.isInterface())
309                                 modifiers |= AccPublic;
310                 } else if (sourceType.isLocalType()) {
311                         if (sourceType.isAnonymousType())
312                                 modifiers |= AccFinal;
313                         ReferenceContext refContext = methodScope().referenceContext;
314                         if (refContext instanceof TypeDeclaration) {
315                                 ReferenceBinding type = ((TypeDeclaration) refContext).binding;
316                                 if (type.isStrictfp())
317                                         modifiers |= AccStrictfp;
318                                 if (type.isDeprecated())
319                                         modifiers |= AccDeprecatedImplicitly;
320                         } else {
321                                 MethodBinding method = ((AbstractMethodDeclaration) refContext).binding;
322                                 if (method != null){
323                                         if (method.isStrictfp())
324                                                 modifiers |= AccStrictfp;
325                                         if (method.isDeprecated())
326                                                 modifiers |= AccDeprecatedImplicitly;
327                                 }
328                         }
329                 }
330                 // after this point, tests on the 16 bits reserved.
331                 int realModifiers = modifiers & AccJustFlag;
332
333                 if ((realModifiers & AccInterface) != 0) {
334                         // detect abnormal cases for interfaces
335                         if (isMemberType) {
336                                 int unexpectedModifiers =
337                                         ~(AccPublic | AccPrivate | AccProtected | AccStatic | AccAbstract | AccInterface | AccStrictfp);
338                                 if ((realModifiers & unexpectedModifiers) != 0)
339                                         problemReporter().illegalModifierForMemberInterface(sourceType);
340                                 /*
341                                 } else if (sourceType.isLocalType()) { //interfaces cannot be defined inside a method
342                                         int unexpectedModifiers = ~(AccAbstract | AccInterface | AccStrictfp);
343                                         if ((realModifiers & unexpectedModifiers) != 0)
344                                                 problemReporter().illegalModifierForLocalInterface(sourceType);
345                                 */
346                         } else {
347                                 int unexpectedModifiers = ~(AccPublic | AccAbstract | AccInterface | AccStrictfp);
348                                 if ((realModifiers & unexpectedModifiers) != 0)
349                                         problemReporter().illegalModifierForInterface(sourceType);
350                         }
351                         modifiers |= AccAbstract;
352                 } else {
353                         // detect abnormal cases for types
354                         if (isMemberType) { // includes member types defined inside local types
355                                 int unexpectedModifiers =
356                                         ~(AccPublic | AccPrivate | AccProtected | AccStatic | AccAbstract | AccFinal | AccStrictfp);
357                                 if ((realModifiers & unexpectedModifiers) != 0)
358                                         problemReporter().illegalModifierForMemberClass(sourceType);
359                         } else if (sourceType.isLocalType()) {
360                                 int unexpectedModifiers = ~(AccAbstract | AccFinal | AccStrictfp);
361                                 if ((realModifiers & unexpectedModifiers) != 0)
362                                         problemReporter().illegalModifierForLocalClass(sourceType);
363                         } else {
364                                 int unexpectedModifiers = ~(AccPublic | AccAbstract | AccFinal | AccStrictfp);
365                                 if ((realModifiers & unexpectedModifiers) != 0)
366                                         problemReporter().illegalModifierForClass(sourceType);
367                         }
368
369                         // check that Final and Abstract are not set together
370                         if ((realModifiers & (AccFinal | AccAbstract)) == (AccFinal | AccAbstract))
371                                 problemReporter().illegalModifierCombinationFinalAbstractForClass(sourceType);
372                 }
373
374                 if (isMemberType) {
375                         // test visibility modifiers inconsistency, isolate the accessors bits
376                         if (enclosingType.isInterface()) {
377                                 if ((realModifiers & (AccProtected | AccPrivate)) != 0) {
378                                         problemReporter().illegalVisibilityModifierForInterfaceMemberType(sourceType);
379
380                                         // need to keep the less restrictive
381                                         if ((realModifiers & AccProtected) != 0)
382                                                 modifiers ^= AccProtected;
383                                         if ((realModifiers & AccPrivate) != 0)
384                                                 modifiers ^= AccPrivate;
385                                 }
386                         } else {
387                                 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
388                                 if ((accessorBits & (accessorBits - 1)) > 1) {
389                                         problemReporter().illegalVisibilityModifierCombinationForMemberType(sourceType);
390
391                                         // need to keep the less restrictive
392                                         if ((accessorBits & AccPublic) != 0) {
393                                                 if ((accessorBits & AccProtected) != 0)
394                                                         modifiers ^= AccProtected;
395                                                 if ((accessorBits & AccPrivate) != 0)
396                                                         modifiers ^= AccPrivate;
397                                         }
398                                         if ((accessorBits & AccProtected) != 0)
399                                                 if ((accessorBits & AccPrivate) != 0)
400                                                         modifiers ^= AccPrivate;
401                                 }
402                         }
403
404                         // static modifier test
405                         if ((realModifiers & AccStatic) == 0) {
406                                 if (enclosingType.isInterface())
407                                         modifiers |= AccStatic;
408                         } else {
409                                 if (!enclosingType.isStatic())
410                                         // error the enclosing type of a static field must be static or a top-level type
411                                         problemReporter().illegalStaticModifierForMemberType(sourceType);
412                         }
413                 }
414
415                 sourceType.modifiers = modifiers;
416         }
417         
418         /* This method checks the modifiers of a field.
419         *
420         * 9.3 & 8.3
421         * Need to integrate the check for the final modifiers for nested types
422         *
423         * Note : A scope is accessible by : fieldBinding.declaringClass.scope
424         */
425         private void checkAndSetModifiersForField(FieldBinding fieldBinding, FieldDeclaration fieldDecl) {
426                 int modifiers = fieldBinding.modifiers;
427                 if ((modifiers & AccAlternateModifierProblem) != 0)
428                         problemReporter().duplicateModifierForField(fieldBinding.declaringClass, fieldDecl);
429
430                 if (fieldBinding.declaringClass.isInterface()) {
431                         int expectedValue = AccPublic | AccStatic | AccFinal;
432                         // set the modifiers
433                         modifiers |= expectedValue;
434
435                         // and then check that they are the only ones
436                         if ((modifiers & AccJustFlag) != expectedValue)
437                                 problemReporter().illegalModifierForInterfaceField(fieldBinding.declaringClass, fieldDecl);
438                         fieldBinding.modifiers = modifiers;
439                         return;
440                 }
441
442                 // after this point, tests on the 16 bits reserved.
443                 int realModifiers = modifiers & AccJustFlag;
444                 int unexpectedModifiers =
445                         ~(AccPublic | AccPrivate | AccProtected | AccFinal | AccStatic | AccTransient | AccVolatile);
446                 if ((realModifiers & unexpectedModifiers) != 0)
447                         problemReporter().illegalModifierForField(fieldBinding.declaringClass, fieldDecl);
448
449                 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
450                 if ((accessorBits & (accessorBits - 1)) > 1) {
451                         problemReporter().illegalVisibilityModifierCombinationForField(
452                                 fieldBinding.declaringClass,
453                                 fieldDecl);
454
455                         // need to keep the less restrictive
456                         if ((accessorBits & AccPublic) != 0) {
457                                 if ((accessorBits & AccProtected) != 0)
458                                         modifiers ^= AccProtected;
459                                 if ((accessorBits & AccPrivate) != 0)
460                                         modifiers ^= AccPrivate;
461                         }
462                         if ((accessorBits & AccProtected) != 0)
463                                 if ((accessorBits & AccPrivate) != 0)
464                                         modifiers ^= AccPrivate;
465                 }
466
467                 if ((realModifiers & (AccFinal | AccVolatile)) == (AccFinal | AccVolatile))
468                         problemReporter().illegalModifierCombinationFinalVolatileForField(
469                                 fieldBinding.declaringClass,
470                                 fieldDecl);
471
472                 fieldBinding.modifiers = modifiers;
473         }
474         
475         private void checkForInheritedMemberTypes(SourceTypeBinding sourceType) {
476                 // search up the hierarchy of the sourceType to see if any superType defines a member type
477                 // when no member types are defined, tag the sourceType & each superType with the HasNoMemberTypes bit
478                 ReferenceBinding currentType = sourceType;
479                 ReferenceBinding[][] interfacesToVisit = null;
480                 int lastPosition = -1;
481                 do {
482                         if ((currentType.tagBits & HasNoMemberTypes) != 0)
483                                 break; // already know it has no inherited member types, can stop looking up
484                         if (currentType.memberTypes() != NoMemberTypes)
485                                 return; // has member types
486                         ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
487                         if (itsInterfaces != NoSuperInterfaces) {
488                                 if (interfacesToVisit == null)
489                                         interfacesToVisit = new ReferenceBinding[5][];
490                                 if (++lastPosition == interfacesToVisit.length)
491                                         System.arraycopy(
492                                                 interfacesToVisit,
493                                                 0,
494                                                 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
495                                                 0,
496                                                 lastPosition);
497                                 interfacesToVisit[lastPosition] = itsInterfaces;
498                         }
499                 } while ((currentType = currentType.superclass()) != null);
500
501                 boolean hasMembers = false;
502                 if (interfacesToVisit != null) {
503                         done : for (int i = 0; i <= lastPosition; i++) {
504                                 ReferenceBinding[] interfaces = interfacesToVisit[i];
505                                 for (int j = 0, length = interfaces.length; j < length; j++) {
506                                         ReferenceBinding anInterface = interfaces[j];
507                                         if ((anInterface.tagBits & InterfaceVisited) == 0) { // if interface as not already been visited
508                                                 anInterface.tagBits |= InterfaceVisited;
509                                                 if ((anInterface.tagBits & HasNoMemberTypes) != 0)
510                                                         continue; // already know it has no inherited member types
511                                                 if (anInterface.memberTypes() != NoMemberTypes) {
512                                                         hasMembers = true;
513                                                         break done;
514                                                 }
515
516                                                 ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
517                                                 if (itsInterfaces != NoSuperInterfaces) {
518                                                         if (++lastPosition == interfacesToVisit.length)
519                                                                 System.arraycopy(
520                                                                         interfacesToVisit,
521                                                                         0,
522                                                                         interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
523                                                                         0,
524                                                                         lastPosition);
525                                                         interfacesToVisit[lastPosition] = itsInterfaces;
526                                                 }
527                                         }
528                                 }
529                         }
530
531                         for (int i = 0; i <= lastPosition; i++) {
532                                 ReferenceBinding[] interfaces = interfacesToVisit[i];
533                                 for (int j = 0, length = interfaces.length; j < length; j++) {
534                                         interfaces[j].tagBits &= ~InterfaceVisited;
535                                         if (!hasMembers)
536                                                 interfaces[j].tagBits |= HasNoMemberTypes;
537                                 }
538                         }
539                 }
540
541                 if (!hasMembers) {
542                         currentType = sourceType;
543                         do {
544                                 currentType.tagBits |= HasNoMemberTypes;
545                         } while ((currentType = currentType.superclass()) != null);
546                 }
547         }
548         
549         private void connectMemberTypes() {
550                 SourceTypeBinding sourceType = referenceContext.binding;
551                 if (sourceType.memberTypes != NoMemberTypes)
552                         for (int i = 0, size = sourceType.memberTypes.length; i < size; i++)
553                                  ((SourceTypeBinding) sourceType.memberTypes[i]).scope.connectTypeHierarchy();
554         }
555         /*
556                 Our current belief based on available JCK tests is:
557                         inherited member types are visible as a potential superclass.
558                         inherited interfaces are not visible when defining a superinterface.
559         
560                 Error recovery story:
561                         ensure the superclass is set to java.lang.Object if a problem is detected
562                         resolving the superclass.
563         
564                 Answer false if an error was reported against the sourceType.
565         */
566         private boolean connectSuperclass() {
567                 SourceTypeBinding sourceType = referenceContext.binding;
568                 if (referenceContext.superclass == null) {
569                         if (isJavaLangObject(sourceType))
570                                 return true;
571                         sourceType.superclass = getJavaLangObject();
572                         return !detectCycle(sourceType, sourceType.superclass, null);
573                         // ensure Object is initialized if it comes from a source file
574                 }
575                 ReferenceBinding superclass = findSupertype(referenceContext.superclass);
576                 if (superclass != null) { // is null if a cycle was detected cycle
577                         if (!superclass.isValidBinding()) {
578                                 problemReporter().invalidSuperclass(sourceType, referenceContext.superclass, superclass);
579                         } else if (superclass.isInterface()) {
580                                 problemReporter().superclassMustBeAClass(sourceType, referenceContext.superclass, superclass);
581                         } else if (superclass.isFinal()) {
582                                 problemReporter().classExtendFinalClass(sourceType, referenceContext.superclass, superclass);
583                         } else if (isJavaLangObject(sourceType)) {
584                                 // can only happen if Object extends another type... will never happen unless we're testing for it.
585                                 sourceType.tagBits |= HierarchyHasProblems;
586                                 sourceType.superclass = null;
587                                 return true;
588                         } else {
589                                 // only want to reach here when no errors are reported
590                                 referenceContext.superclass.binding = superclass;
591                                 sourceType.superclass = superclass;
592                                 return true;
593                         }
594                 }
595                 sourceType.tagBits |= HierarchyHasProblems;
596                 if (!isJavaLangObject(sourceType)) {
597                         sourceType.superclass = getJavaLangObject();
598                         if ((sourceType.superclass.tagBits & BeginHierarchyCheck) == 0)
599                                 detectCycle(sourceType, sourceType.superclass, null);
600                         // ensure Object is initialized if it comes from a source file
601                 }
602                 return false; // reported some error against the source type
603         }
604
605         /*
606                 Our current belief based on available JCK 1.3 tests is:
607                         inherited member types are visible as a potential superclass.
608                         inherited interfaces are visible when defining a superinterface.
609         
610                 Error recovery story:
611                         ensure the superinterfaces contain only valid visible interfaces.
612         
613                 Answer false if an error was reported against the sourceType.
614         */
615         private boolean connectSuperInterfaces() {
616                 SourceTypeBinding sourceType = referenceContext.binding;
617                 sourceType.superInterfaces = NoSuperInterfaces;
618                 if (referenceContext.superInterfaces == null)
619                         return true;
620
621                 boolean noProblems = true;
622                 int length = referenceContext.superInterfaces.length;
623                 ReferenceBinding[] interfaceBindings = new ReferenceBinding[length];
624                 int count = 0;
625                 nextInterface : for (int i = 0; i < length; i++) {
626                         ReferenceBinding superInterface = findSupertype(referenceContext.superInterfaces[i]);
627                         if (superInterface == null) { // detected cycle
628                                 noProblems = false;
629                                 continue nextInterface;
630                         }
631                         if (!superInterface.isValidBinding()) {
632                                 problemReporter().invalidSuperinterface(
633                                         sourceType,
634                                         referenceContext.superInterfaces[i],
635                                         superInterface);
636                                 sourceType.tagBits |= HierarchyHasProblems;
637                                 noProblems = false;
638                                 continue nextInterface;
639                         }
640                         // Check for a duplicate interface once the name is resolved, otherwise we may be confused (ie : a.b.I and c.d.I)
641                         for (int k = 0; k < count; k++) {
642                                 if (interfaceBindings[k] == superInterface) {
643                                         // should this be treated as a warning?
644                                         problemReporter().duplicateSuperinterface(sourceType, referenceContext, superInterface);
645                                         continue nextInterface;
646                                 }
647                         }
648                         if (superInterface.isClass()) {
649                                 problemReporter().superinterfaceMustBeAnInterface(sourceType, referenceContext, superInterface);
650                                 sourceType.tagBits |= HierarchyHasProblems;
651                                 noProblems = false;
652                                 continue nextInterface;
653                         }
654                         referenceContext.superInterfaces[i].binding = superInterface;
655                         // only want to reach here when no errors are reported
656                         interfaceBindings[count++] = superInterface;
657                 }
658                 // hold onto all correctly resolved superinterfaces
659                 if (count > 0) {
660                         if (count != length)
661                                 System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[count], 0, count);
662                         sourceType.superInterfaces = interfaceBindings;
663                 }
664                 return noProblems;
665         }
666         
667         void connectTypeHierarchy() {
668                 SourceTypeBinding sourceType = referenceContext.binding;
669                 if ((sourceType.tagBits & BeginHierarchyCheck) == 0) {
670                         boolean noProblems = true;
671                         sourceType.tagBits |= BeginHierarchyCheck;
672                         if (sourceType.isClass())
673                                 noProblems &= connectSuperclass();
674                         noProblems &= connectSuperInterfaces();
675                         sourceType.tagBits |= EndHierarchyCheck;
676                         if (noProblems && sourceType.isHierarchyInconsistent())
677                                 problemReporter().hierarchyHasProblems(sourceType);
678                 }
679                 connectMemberTypes();
680                 checkForInheritedMemberTypes(sourceType);
681         }
682         
683         private void connectTypeHierarchyWithoutMembers() {
684                 // must ensure the imports are resolved
685                 if (parent instanceof CompilationUnitScope) {
686                         if (((CompilationUnitScope) parent).imports == null)
687                                  ((CompilationUnitScope) parent).checkAndSetImports();
688                 } else if (parent instanceof ClassScope) {
689                         // ensure that the enclosing type has already been checked
690                          ((ClassScope) parent).connectTypeHierarchyWithoutMembers();
691                 }
692
693                 // double check that the hierarchy search has not already begun...
694                 SourceTypeBinding sourceType = referenceContext.binding;
695                 if ((sourceType.tagBits & BeginHierarchyCheck) != 0)
696                         return;
697
698                 boolean noProblems = true;
699                 sourceType.tagBits |= BeginHierarchyCheck;
700                 if (sourceType.isClass())
701                         noProblems &= connectSuperclass();
702                 noProblems &= connectSuperInterfaces();
703                 sourceType.tagBits |= EndHierarchyCheck;
704                 if (noProblems && sourceType.isHierarchyInconsistent())
705                         problemReporter().hierarchyHasProblems(sourceType);
706         }
707         
708         // Answer whether a cycle was found between the sourceType & the superType
709         private boolean detectCycle(
710                 SourceTypeBinding sourceType,
711                 ReferenceBinding superType,
712                 TypeReference reference) {
713                 if (sourceType == superType) {
714                         problemReporter().hierarchyCircularity(sourceType, superType, reference);
715                         sourceType.tagBits |= HierarchyHasProblems;
716                         return true;
717                 }
718
719                 if (superType.isBinaryBinding()) {
720                         // force its superclass & superinterfaces to be found... 2 possibilities exist - the source type is included in the hierarchy of:
721                         //              - a binary type... this case MUST be caught & reported here
722                         //              - another source type... this case is reported against the other source type
723                         boolean hasCycle = false;
724                         if (superType.superclass() != null) {
725                                 if (sourceType == superType.superclass()) {
726                                         problemReporter().hierarchyCircularity(sourceType, superType, reference);
727                                         sourceType.tagBits |= HierarchyHasProblems;
728                                         superType.tagBits |= HierarchyHasProblems;
729                                         return true;
730                                 }
731                                 hasCycle |= detectCycle(sourceType, superType.superclass(), reference);
732                                 if ((superType.superclass().tagBits & HierarchyHasProblems) != 0) {
733                                         sourceType.tagBits |= HierarchyHasProblems;
734                                         superType.tagBits |= HierarchyHasProblems; // propagate down the hierarchy
735                                 }
736                         }
737
738                         ReferenceBinding[] itsInterfaces = superType.superInterfaces();
739                         if (itsInterfaces != NoSuperInterfaces) {
740                                 for (int i = 0, length = itsInterfaces.length; i < length; i++) {
741                                         ReferenceBinding anInterface = itsInterfaces[i];
742                                         if (sourceType == anInterface) {
743                                                 problemReporter().hierarchyCircularity(sourceType, superType, reference);
744                                                 sourceType.tagBits |= HierarchyHasProblems;
745                                                 superType.tagBits |= HierarchyHasProblems;
746                                                 return true;
747                                         }
748                                         hasCycle |= detectCycle(sourceType, anInterface, reference);
749                                         if ((anInterface.tagBits & HierarchyHasProblems) != 0) {
750                                                 sourceType.tagBits |= HierarchyHasProblems;
751                                                 superType.tagBits |= HierarchyHasProblems;
752                                         }
753                                 }
754                         }
755                         return hasCycle;
756                 }
757
758                 if ((superType.tagBits & EndHierarchyCheck) == 0
759                         && (superType.tagBits & BeginHierarchyCheck) != 0) {
760                         problemReporter().hierarchyCircularity(sourceType, superType, reference);
761                         sourceType.tagBits |= HierarchyHasProblems;
762                         superType.tagBits |= HierarchyHasProblems;
763                         return true;
764                 }
765                 if ((superType.tagBits & BeginHierarchyCheck) == 0)
766                         // ensure if this is a source superclass that it has already been checked
767                          ((SourceTypeBinding) superType).scope.connectTypeHierarchyWithoutMembers();
768                 if ((superType.tagBits & HierarchyHasProblems) != 0)
769                         sourceType.tagBits |= HierarchyHasProblems;
770                 return false;
771         }
772         
773         private ReferenceBinding findSupertype(TypeReference typeReference) {
774                 typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes
775                 char[][] compoundName = typeReference.getTypeName();
776                 compilationUnitScope().recordQualifiedReference(compoundName);
777                 SourceTypeBinding sourceType = referenceContext.binding;
778                 int size = compoundName.length;
779                 int n = 1;
780                 ReferenceBinding superType;
781
782                 // resolve the first name of the compoundName
783                 if (CharOperation.equals(compoundName[0], sourceType.sourceName)) {
784                         superType = sourceType;
785                         // match against the sourceType even though nested members cannot be supertypes
786                 } else {
787                         Binding typeOrPackage = parent.getTypeOrPackage(compoundName[0], TYPE | PACKAGE);
788                         if (typeOrPackage == null || !typeOrPackage.isValidBinding())
789                                 return new ProblemReferenceBinding(
790                                         compoundName[0],
791                                         typeOrPackage == null ? NotFound : typeOrPackage.problemId());
792
793                         boolean checkVisibility = false;
794                         for (; n < size; n++) {
795                                 if (!(typeOrPackage instanceof PackageBinding))
796                                         break;
797                                 PackageBinding packageBinding = (PackageBinding) typeOrPackage;
798                                 typeOrPackage = packageBinding.getTypeOrPackage(compoundName[n]);
799                                 if (typeOrPackage == null || !typeOrPackage.isValidBinding())
800                                         return new ProblemReferenceBinding(
801                                                 CharOperation.subarray(compoundName, 0, n + 1),
802                                                 typeOrPackage == null ? NotFound : typeOrPackage.problemId());
803                                 checkVisibility = true;
804                         }
805
806                         // convert to a ReferenceBinding
807                         if (typeOrPackage instanceof PackageBinding) // error, the compoundName is a packageName
808                                 return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound);
809                         superType = (ReferenceBinding) typeOrPackage;
810                         compilationUnitScope().recordTypeReference(superType); // to record supertypes
811
812                         if (checkVisibility
813                                 && n == size) { // if we're finished and know the final supertype then check visibility
814                                 if (!superType.canBeSeenBy(sourceType.fPackage))
815                                         // its a toplevel type so just check package access
816                                         return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), superType, NotVisible);
817                         }
818                 }
819                 // at this point we know we have a type but we have to look for cycles
820                 while (true) {
821                         // must detect cycles & force connection up the hierarchy... also handle cycles with binary types.
822                         // must be guaranteed that the superType knows its entire hierarchy
823                         if (detectCycle(sourceType, superType, typeReference))
824                                 return null; // cycle error was already reported
825
826                         if (n >= size)
827                                 break;
828
829                         // retrieve the next member type
830                         char[] typeName = compoundName[n++];
831                         superType = findMemberType(typeName, superType);
832                         if (superType == null)
833                                 return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound);
834                         if (!superType.isValidBinding()) {
835                                 superType.compoundName = CharOperation.subarray(compoundName, 0, n);
836                                 return superType;
837                         }
838                 }
839                 return superType;
840         }
841
842         /* Answer the problem reporter to use for raising new problems.
843         *
844         * Note that as a side-effect, this updates the current reference context
845         * (unit, type or method) in case the problem handler decides it is necessary
846         * to abort.
847         */
848         public ProblemReporter problemReporter() {
849                 MethodScope outerMethodScope;
850                 if ((outerMethodScope = outerMostMethodScope()) == null) {
851                         ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
852                         problemReporter.referenceContext = referenceContext;
853                         return problemReporter;
854                 } else {
855                         return outerMethodScope.problemReporter();
856                 }
857         }
858
859         /* Answer the reference type of this scope.
860         *
861         * i.e. the nearest enclosing type of this scope.
862         */
863         public TypeDeclaration referenceType() {
864                 return referenceContext;
865         }
866         
867         public String toString() {
868                 if (referenceContext != null)
869                         return "--- Class Scope ---\n\n"  //$NON-NLS-1$
870                         +referenceContext.binding.toString();
871                 else
872                         return "--- Class Scope ---\n\n Binding not initialized" ; //$NON-NLS-1$
873         }
874 }