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