Basic Reafctoring functionality adapted from Leif Frenzels sources in eclipse-magazin...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / lookup / ClassScope.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.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.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
15 import net.sourceforge.phpdt.internal.compiler.ast.Clinit;
16 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
17 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
18 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
19 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
20 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
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                 if (fieldDecl.initialization == null && (modifiers & AccFinal) != 0) {
473                         modifiers |= AccBlankFinal;
474                 }
475                 fieldBinding.modifiers = modifiers;
476         }
477         
478         private void checkForInheritedMemberTypes(SourceTypeBinding sourceType) {
479                 // search up the hierarchy of the sourceType to see if any superType defines a member type
480                 // when no member types are defined, tag the sourceType & each superType with the HasNoMemberTypes bit
481                 ReferenceBinding currentType = sourceType;
482                 ReferenceBinding[][] interfacesToVisit = null;
483                 int lastPosition = -1;
484                 do {
485                         if ((currentType.tagBits & HasNoMemberTypes) != 0)
486                                 break; // already know it has no inherited member types, can stop looking up
487                         if (currentType.memberTypes() != NoMemberTypes)
488                                 return; // has member types
489                         ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
490                         if (itsInterfaces != NoSuperInterfaces) {
491                                 if (interfacesToVisit == null)
492                                         interfacesToVisit = new ReferenceBinding[5][];
493                                 if (++lastPosition == interfacesToVisit.length)
494                                         System.arraycopy(
495                                                 interfacesToVisit,
496                                                 0,
497                                                 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
498                                                 0,
499                                                 lastPosition);
500                                 interfacesToVisit[lastPosition] = itsInterfaces;
501                         }
502                 } while ((currentType = currentType.superclass()) != null);
503
504                 boolean hasMembers = false;
505                 if (interfacesToVisit != null) {
506                         done : for (int i = 0; i <= lastPosition; i++) {
507                                 ReferenceBinding[] interfaces = interfacesToVisit[i];
508                                 for (int j = 0, length = interfaces.length; j < length; j++) {
509                                         ReferenceBinding anInterface = interfaces[j];
510                                         if ((anInterface.tagBits & InterfaceVisited) == 0) { // if interface as not already been visited
511                                                 anInterface.tagBits |= InterfaceVisited;
512                                                 if ((anInterface.tagBits & HasNoMemberTypes) != 0)
513                                                         continue; // already know it has no inherited member types
514                                                 if (anInterface.memberTypes() != NoMemberTypes) {
515                                                         hasMembers = true;
516                                                         break done;
517                                                 }
518
519                                                 ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
520                                                 if (itsInterfaces != NoSuperInterfaces) {
521                                                         if (++lastPosition == interfacesToVisit.length)
522                                                                 System.arraycopy(
523                                                                         interfacesToVisit,
524                                                                         0,
525                                                                         interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
526                                                                         0,
527                                                                         lastPosition);
528                                                         interfacesToVisit[lastPosition] = itsInterfaces;
529                                                 }
530                                         }
531                                 }
532                         }
533
534                         for (int i = 0; i <= lastPosition; i++) {
535                                 ReferenceBinding[] interfaces = interfacesToVisit[i];
536                                 for (int j = 0, length = interfaces.length; j < length; j++) {
537                                         interfaces[j].tagBits &= ~InterfaceVisited;
538                                         if (!hasMembers)
539                                                 interfaces[j].tagBits |= HasNoMemberTypes;
540                                 }
541                         }
542                 }
543
544                 if (!hasMembers) {
545                         currentType = sourceType;
546                         do {
547                                 currentType.tagBits |= HasNoMemberTypes;
548                         } while ((currentType = currentType.superclass()) != null);
549                 }
550         }
551         
552         private void connectMemberTypes() {
553                 SourceTypeBinding sourceType = referenceContext.binding;
554                 if (sourceType.memberTypes != NoMemberTypes)
555                         for (int i = 0, size = sourceType.memberTypes.length; i < size; i++)
556                                  ((SourceTypeBinding) sourceType.memberTypes[i]).scope.connectTypeHierarchy();
557         }
558         /*
559                 Our current belief based on available JCK tests is:
560                         inherited member types are visible as a potential superclass.
561                         inherited interfaces are not visible when defining a superinterface.
562         
563                 Error recovery story:
564                         ensure the superclass is set to java.lang.Object if a problem is detected
565                         resolving the superclass.
566         
567                 Answer false if an error was reported against the sourceType.
568         */
569         private boolean connectSuperclass() {
570                 SourceTypeBinding sourceType = referenceContext.binding;
571                 if (isJavaLangObject(sourceType)) { // handle the case of redefining java.lang.Object up front
572                         sourceType.superclass = null;
573                         sourceType.superInterfaces = NoSuperInterfaces;
574                         if (referenceContext.superclass != null || referenceContext.superInterfaces != null)
575                                 problemReporter().objectCannotHaveSuperTypes(sourceType);
576                         return true; // do not propagate Object's hierarchy problems down to every subtype
577                 }
578                 if (referenceContext.superclass == null) {
579                         sourceType.superclass = getJavaLangObject();
580                         return !detectCycle(sourceType, sourceType.superclass, null);
581                 }
582                 ReferenceBinding superclass = findSupertype(referenceContext.superclass);
583                 if (superclass != null) { // is null if a cycle was detected cycle
584                         if (!superclass.isValidBinding()) {
585                                 problemReporter().invalidSuperclass(sourceType, referenceContext.superclass, superclass);
586                         } else if (superclass.isInterface()) {
587                                 problemReporter().superclassMustBeAClass(sourceType, referenceContext.superclass, superclass);
588                         } else if (superclass.isFinal()) {
589                                 problemReporter().classExtendFinalClass(sourceType, referenceContext.superclass, superclass);
590                         } else {
591                                 // only want to reach here when no errors are reported
592                                 referenceContext.superclass.resolvedType = superclass;
593                                 sourceType.superclass = superclass;
594                                 return true;
595                         }
596                 }
597                 sourceType.tagBits |= HierarchyHasProblems;
598                 sourceType.superclass = getJavaLangObject();
599                 if ((sourceType.superclass.tagBits & BeginHierarchyCheck) == 0)
600                         detectCycle(sourceType, sourceType.superclass, null);
601                 return false; // reported some error against the source type
602         }
603
604         /*
605                 Our current belief based on available JCK 1.3 tests is:
606                         inherited member types are visible as a potential superclass.
607                         inherited interfaces are visible when defining a superinterface.
608         
609                 Error recovery story:
610                         ensure the superinterfaces contain only valid visible interfaces.
611         
612                 Answer false if an error was reported against the sourceType.
613         */
614         private boolean connectSuperInterfaces() {
615                 SourceTypeBinding sourceType = referenceContext.binding;
616                 sourceType.superInterfaces = NoSuperInterfaces;
617                 if (referenceContext.superInterfaces == null)
618                         return true;
619                 if (isJavaLangObject(sourceType)) // already handled the case of redefining java.lang.Object
620                         return true;
621
622                 boolean noProblems = true;
623                 int length = referenceContext.superInterfaces.length;
624                 ReferenceBinding[] interfaceBindings = new ReferenceBinding[length];
625                 int count = 0;
626                 nextInterface : for (int i = 0; i < length; i++) {
627                         ReferenceBinding superInterface = findSupertype(referenceContext.superInterfaces[i]);
628                         if (superInterface == null) { // detected cycle
629                                 noProblems = false;
630                                 continue nextInterface;
631                         }
632                         if (!superInterface.isValidBinding()) {
633                                 problemReporter().invalidSuperinterface(
634                                         sourceType,
635                                         referenceContext.superInterfaces[i],
636                                         superInterface);
637                                 sourceType.tagBits |= HierarchyHasProblems;
638                                 noProblems = false;
639                                 continue nextInterface;
640                         }
641                         // Check for a duplicate interface once the name is resolved, otherwise we may be confused (ie : a.b.I and c.d.I)
642                         for (int k = 0; k < count; k++) {
643                                 if (interfaceBindings[k] == superInterface) {
644                                         // should this be treated as a warning?
645                                         problemReporter().duplicateSuperinterface(sourceType, referenceContext, superInterface);
646                                         continue nextInterface;
647                                 }
648                         }
649                         if (superInterface.isClass()) {
650                                 problemReporter().superinterfaceMustBeAnInterface(sourceType, referenceContext, superInterface);
651                                 sourceType.tagBits |= HierarchyHasProblems;
652                                 noProblems = false;
653                                 continue nextInterface;
654                         }
655
656                         referenceContext.superInterfaces[i].resolvedType = superInterface;
657                         // only want to reach here when no errors are reported
658                         interfaceBindings[count++] = superInterface;
659                 }
660                 // hold onto all correctly resolved superinterfaces
661                 if (count > 0) {
662                         if (count != length)
663                                 System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[count], 0, count);
664                         sourceType.superInterfaces = interfaceBindings;
665                 }
666                 return noProblems;
667         }
668         
669         void connectTypeHierarchy() {
670                 SourceTypeBinding sourceType = referenceContext.binding;
671                 if ((sourceType.tagBits & BeginHierarchyCheck) == 0) {
672                         boolean noProblems = true;
673                         sourceType.tagBits |= BeginHierarchyCheck;
674                         if (sourceType.isClass())
675                                 noProblems &= connectSuperclass();
676                         noProblems &= connectSuperInterfaces();
677                         sourceType.tagBits |= EndHierarchyCheck;
678                         if (noProblems && sourceType.isHierarchyInconsistent())
679                                 problemReporter().hierarchyHasProblems(sourceType);
680                 }
681                 connectMemberTypes();
682                 checkForInheritedMemberTypes(sourceType);
683         }
684         
685         private void connectTypeHierarchyWithoutMembers() {
686                 // must ensure the imports are resolved
687                 if (parent instanceof CompilationUnitScope) {
688 //                      if (((CompilationUnitScope) parent).imports == null)
689 //                               ((CompilationUnitScope) parent).checkAndSetImports();
690                 } else if (parent instanceof ClassScope) {
691                         // ensure that the enclosing type has already been checked
692                          ((ClassScope) parent).connectTypeHierarchyWithoutMembers();
693                 }
694
695                 // double check that the hierarchy search has not already begun...
696                 SourceTypeBinding sourceType = referenceContext.binding;
697                 if ((sourceType.tagBits & BeginHierarchyCheck) != 0)
698                         return;
699
700                 boolean noProblems = true;
701                 sourceType.tagBits |= BeginHierarchyCheck;
702                 if (sourceType.isClass())
703                         noProblems &= connectSuperclass();
704                 noProblems &= connectSuperInterfaces();
705                 sourceType.tagBits |= EndHierarchyCheck;
706                 if (noProblems && sourceType.isHierarchyInconsistent())
707                         problemReporter().hierarchyHasProblems(sourceType);
708         }
709         
710         // Answer whether a cycle was found between the sourceType & the superType
711         private boolean detectCycle(
712                 SourceTypeBinding sourceType,
713                 ReferenceBinding superType,
714                 TypeReference reference) {
715                 if (sourceType == superType) {
716                         problemReporter().hierarchyCircularity(sourceType, superType, reference);
717                         sourceType.tagBits |= HierarchyHasProblems;
718                         return true;
719                 }
720
721                 if (superType.isBinaryBinding()) {
722                         // force its superclass & superinterfaces to be found... 2 possibilities exist - the source type is included in the hierarchy of:
723                         //              - a binary type... this case MUST be caught & reported here
724                         //              - another source type... this case is reported against the other source type
725                         boolean hasCycle = false;
726                         if (superType.superclass() != null) {
727                                 if (sourceType == superType.superclass()) {
728                                         problemReporter().hierarchyCircularity(sourceType, superType, reference);
729                                         sourceType.tagBits |= HierarchyHasProblems;
730                                         superType.tagBits |= HierarchyHasProblems;
731                                         return true;
732                                 }
733                                 hasCycle |= detectCycle(sourceType, superType.superclass(), reference);
734                                 if ((superType.superclass().tagBits & HierarchyHasProblems) != 0) {
735                                         sourceType.tagBits |= HierarchyHasProblems;
736                                         superType.tagBits |= HierarchyHasProblems; // propagate down the hierarchy
737                                 }
738                         }
739
740                         ReferenceBinding[] itsInterfaces = superType.superInterfaces();
741                         if (itsInterfaces != NoSuperInterfaces) {
742                                 for (int i = 0, length = itsInterfaces.length; i < length; i++) {
743                                         ReferenceBinding anInterface = itsInterfaces[i];
744                                         if (sourceType == anInterface) {
745                                                 problemReporter().hierarchyCircularity(sourceType, superType, reference);
746                                                 sourceType.tagBits |= HierarchyHasProblems;
747                                                 superType.tagBits |= HierarchyHasProblems;
748                                                 return true;
749                                         }
750                                         hasCycle |= detectCycle(sourceType, anInterface, reference);
751                                         if ((anInterface.tagBits & HierarchyHasProblems) != 0) {
752                                                 sourceType.tagBits |= HierarchyHasProblems;
753                                                 superType.tagBits |= HierarchyHasProblems;
754                                         }
755                                 }
756                         }
757                         return hasCycle;
758                 }
759
760                 if ((superType.tagBits & EndHierarchyCheck) == 0
761                         && (superType.tagBits & BeginHierarchyCheck) != 0) {
762                         problemReporter().hierarchyCircularity(sourceType, superType, reference);
763                         sourceType.tagBits |= HierarchyHasProblems;
764                         superType.tagBits |= HierarchyHasProblems;
765                         return true;
766                 }
767                 if ((superType.tagBits & BeginHierarchyCheck) == 0)
768                         // ensure if this is a source superclass that it has already been checked
769                          ((SourceTypeBinding) superType).scope.connectTypeHierarchyWithoutMembers();
770                 if ((superType.tagBits & HierarchyHasProblems) != 0)
771                         sourceType.tagBits |= HierarchyHasProblems;
772                 return false;
773         }
774         
775         private ReferenceBinding findSupertype(TypeReference typeReference) {
776                 typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes
777                 char[][] compoundName = typeReference.getTypeName();
778                 compilationUnitScope().recordQualifiedReference(compoundName);
779                 SourceTypeBinding sourceType = referenceContext.binding;
780                 int size = compoundName.length;
781                 int n = 1;
782                 ReferenceBinding superType;
783
784                 // resolve the first name of the compoundName
785                 if (CharOperation.equals(compoundName[0], sourceType.sourceName)) {
786                         superType = sourceType;
787                         // match against the sourceType even though nested members cannot be supertypes
788                 } else {
789                         Binding typeOrPackage = parent.getTypeOrPackage(compoundName[0], TYPE | PACKAGE);
790                         if (typeOrPackage == null || !typeOrPackage.isValidBinding())
791                                 return new ProblemReferenceBinding(
792                                         compoundName[0],
793                                         typeOrPackage == null ? NotFound : typeOrPackage.problemId());
794
795                         boolean checkVisibility = false;
796                         for (; n < size; n++) {
797                                 if (!(typeOrPackage instanceof PackageBinding))
798                                         break;
799                                 PackageBinding packageBinding = (PackageBinding) typeOrPackage;
800                                 typeOrPackage = packageBinding.getTypeOrPackage(compoundName[n]);
801                                 if (typeOrPackage == null || !typeOrPackage.isValidBinding())
802                                         return new ProblemReferenceBinding(
803                                                 CharOperation.subarray(compoundName, 0, n + 1),
804                                                 typeOrPackage == null ? NotFound : typeOrPackage.problemId());
805                                 checkVisibility = true;
806                         }
807
808                         // convert to a ReferenceBinding
809                         if (typeOrPackage instanceof PackageBinding) // error, the compoundName is a packageName
810                                 return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound);
811                         superType = (ReferenceBinding) typeOrPackage;
812                         compilationUnitScope().recordTypeReference(superType); // to record supertypes
813
814                         if (checkVisibility
815                                 && n == size) { // if we're finished and know the final supertype then check visibility
816                                 if (!superType.canBeSeenBy(sourceType.fPackage))
817                                         // its a toplevel type so just check package access
818                                         return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), superType, NotVisible);
819                         }
820                 }
821                 // at this point we know we have a type but we have to look for cycles
822                 while (true) {
823                         // must detect cycles & force connection up the hierarchy... also handle cycles with binary types.
824                         // must be guaranteed that the superType knows its entire hierarchy
825                         if (detectCycle(sourceType, superType, typeReference))
826                                 return null; // cycle error was already reported
827
828                         if (n >= size)
829                                 break;
830
831                         // retrieve the next member type
832                         char[] typeName = compoundName[n++];
833                         superType = findMemberType(typeName, superType);
834                         if (superType == null)
835                                 return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, n), NotFound);
836                         if (!superType.isValidBinding()) {
837                                 superType.compoundName = CharOperation.subarray(compoundName, 0, n);
838                                 return superType;
839                         }
840                 }
841                 return superType;
842         }
843
844         /* Answer the problem reporter to use for raising new problems.
845         *
846         * Note that as a side-effect, this updates the current reference context
847         * (unit, type or method) in case the problem handler decides it is necessary
848         * to abort.
849         */
850         public ProblemReporter problemReporter() {
851                 MethodScope outerMethodScope;
852                 if ((outerMethodScope = outerMostMethodScope()) == null) {
853                         ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
854                         problemReporter.referenceContext = referenceContext;
855                         return problemReporter;
856                 } else {
857                         return outerMethodScope.problemReporter();
858                 }
859         }
860
861         /* Answer the reference type of this scope.
862         * It is the nearest enclosing type of this scope.
863         */
864         public TypeDeclaration referenceType() {
865                 return referenceContext;
866         }
867         
868         public String toString() {
869                 if (referenceContext != null)
870                         return "--- Class Scope ---\n\n"  //$NON-NLS-1$
871                         +referenceContext.binding.toString();
872                 else
873                         return "--- Class Scope ---\n\n Binding not initialized" ; //$NON-NLS-1$
874         }
875 }