578857ab3bf587bf0178de40e64761241506c3ff
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / TypeDeclaration.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.*;
15 import net.sourceforge.phpdt.internal.compiler.impl.*;
16 import net.sourceforge.phpdt.internal.compiler.codegen.*;
17 import net.sourceforge.phpdt.internal.compiler.flow.*;
18 import net.sourceforge.phpdt.internal.compiler.lookup.*;
19 import net.sourceforge.phpdt.internal.compiler.parser.*;
20 import net.sourceforge.phpdt.internal.compiler.problem.*;
21 import net.sourceforge.phpdt.internal.compiler.util.*;
22
23 public class TypeDeclaration
24         extends Statement
25         implements ProblemSeverities, ReferenceContext {
26
27         public int modifiers;
28         public int modifiersSourceStart;
29         public char[] name;
30         public TypeReference superclass;
31         public TypeReference[] superInterfaces;
32         public FieldDeclaration[] fields;
33         public AbstractMethodDeclaration[] methods;
34         public MemberTypeDeclaration[] memberTypes;
35         public SourceTypeBinding binding;
36         public ClassScope scope;
37         public MethodScope initializerScope;
38         public MethodScope staticInitializerScope;
39         public boolean ignoreFurtherInvestigation = false;
40         public int maxFieldCount;
41         public int declarationSourceStart;
42         public int declarationSourceEnd;
43         public int bodyStart;
44         public int bodyEnd; // doesn't include the trailing comment if any.
45         protected boolean hasBeenGenerated = false;
46         public CompilationResult compilationResult;
47         private MethodDeclaration[] missingAbstractMethods;
48
49         public TypeDeclaration(CompilationResult compilationResult){
50                 this.compilationResult = compilationResult;
51         }
52                 
53         /*
54          *      We cause the compilation task to abort to a given extent.
55          */
56         public void abort(int abortLevel) {
57
58                 if (scope == null) {
59                         throw new AbortCompilation(); // cannot do better
60                 }
61
62                 CompilationResult compilationResult =
63                         scope.referenceCompilationUnit().compilationResult;
64
65                 switch (abortLevel) {
66                         case AbortCompilation :
67                                 throw new AbortCompilation(compilationResult);
68                         case AbortCompilationUnit :
69                                 throw new AbortCompilationUnit(compilationResult);
70                         case AbortMethod :
71                                 throw new AbortMethod(compilationResult);
72                         default :
73                                 throw new AbortType(compilationResult);
74                 }
75         }
76         /**
77          * This method is responsible for adding a <clinit> method declaration to the type method collections.
78          * Note that this implementation is inserting it in first place (as VAJ or javac), and that this
79          * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as 
80          * the latter will have to reset the constant pool state accordingly (if it was added first, it does 
81          * not need to preserve some of the method specific cached entries since this will be the first method).
82          * inserts the clinit method declaration in the first position.
83          * 
84          * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int)
85          */
86         public final void addClinit() {
87
88                 //see comment on needClassInitMethod
89                 if (needClassInitMethod()) {
90                         int length;
91                         AbstractMethodDeclaration[] methods;
92                         if ((methods = this.methods) == null) {
93                                 length = 0;
94                                 methods = new AbstractMethodDeclaration[1];
95                         } else {
96                                 length = methods.length;
97                                 System.arraycopy(
98                                         methods,
99                                         0,
100                                         (methods = new AbstractMethodDeclaration[length + 1]),
101                                         1,
102                                         length);
103                         }
104                         Clinit clinit = new Clinit(this.compilationResult);
105                         methods[0] = clinit;
106                         // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits)
107                         clinit.declarationSourceStart = clinit.sourceStart = sourceStart;
108                         clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd;
109                         clinit.bodyEnd = sourceEnd;
110                         this.methods = methods;
111                 }
112         }
113
114         /**
115          *      Flow analysis for a local innertype
116          *
117          */
118         public FlowInfo analyseCode(
119                 BlockScope currentScope,
120                 FlowContext flowContext,
121                 FlowInfo flowInfo) {
122
123                 if (ignoreFurtherInvestigation)
124                         return flowInfo;
125                 try {
126                         // remember local types binding for innerclass emulation propagation
127                         currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
128
129                         InitializationFlowContext initializerContext =
130                                 new InitializationFlowContext(null, this, initializerScope);
131                         // propagate down the max field count
132                         updateMaxFieldCount();
133                         FlowInfo fieldInfo = flowInfo.copy();
134                         // so as not to propagate changes outside this type
135                         if (fields != null) {
136                                 for (int i = 0, count = fields.length; i < count; i++) {
137                                         fieldInfo =
138                                                 fields[i].analyseCode(initializerScope, initializerContext, fieldInfo);
139                                         if (fieldInfo == FlowInfo.DeadEnd) {
140                                                 // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
141                                                 // branch, since the previous initializer already got the blame.
142                                                 initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
143                                                 fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
144                                         }
145                                 }
146                         }
147                         if (memberTypes != null) {
148                                 for (int i = 0, count = memberTypes.length; i < count; i++) {
149                                         memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
150                                 }
151                         }
152                         if (methods != null) {
153                                 int recursionBalance = 0; // check constructor recursions                       
154                                 for (int i = 0, count = methods.length; i < count; i++) {
155                                         AbstractMethodDeclaration method = methods[i];
156                                         if (method.ignoreFurtherInvestigation)
157                                                 continue;
158                                         if (method.isConstructor()) { // constructor
159                                                 ConstructorDeclaration constructor = (ConstructorDeclaration) method;
160                                                 constructor.analyseCode(scope, initializerContext, fieldInfo.copy());
161                                                 // compute the recursive invocation balance:
162                                                 //   how many thisReferences vs. superReferences to constructors
163                                                 int refCount;
164                                                 if ((refCount = constructor.referenceCount) > 0) {
165                                                         if ((constructor.constructorCall == null)
166                                                                 || constructor.constructorCall.isSuperAccess()
167                                                                 || !constructor.constructorCall.binding.isValidBinding()) {
168                                                                 recursionBalance -= refCount;
169                                                                 constructor.referenceCount = -1;
170                                                                 // for error reporting propagation                                                                                                                              
171                                                         } else {
172                                                                 recursionBalance += refCount;
173                                                         }
174                                                 }
175                                         } else { // regular method
176                                                 method.analyseCode(scope, null, flowInfo.copy());
177                                         }
178                                 }
179                                 if (recursionBalance > 0) {
180                                         // there is one or more cycle(s) amongst constructor invocations
181                                         scope.problemReporter().recursiveConstructorInvocation(this);
182                                 }
183                         }
184                 } catch (AbortType e) {
185                         this.ignoreFurtherInvestigation = true;
186                 }
187                 return flowInfo;
188         }
189
190         /**
191          *      Flow analysis for a member innertype
192          *
193          */
194         public void analyseCode(ClassScope classScope1) {
195
196                 if (ignoreFurtherInvestigation)
197                         return;
198                 try {
199                         // propagate down the max field count
200                         updateMaxFieldCount();
201                         FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info
202                         InitializationFlowContext initializerContext =
203                                 new InitializationFlowContext(null, this, initializerScope);
204                         InitializationFlowContext staticInitializerContext =
205                                 new InitializationFlowContext(null, this, staticInitializerScope);
206                         FlowInfo nonStaticFieldInfo = flowInfo.copy(),
207                                 staticFieldInfo = flowInfo.copy();
208                         if (fields != null) {
209                                 for (int i = 0, count = fields.length; i < count; i++) {
210                                         if (fields[i].isStatic()) {
211                                                 staticFieldInfo =
212                                                         fields[i].analyseCode(
213                                                                 staticInitializerScope,
214                                                                 staticInitializerContext,
215                                                                 staticFieldInfo);
216                                                 // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
217                                                 // branch, since the previous initializer already got the blame.
218                                                 if (staticFieldInfo == FlowInfo.DeadEnd) {
219                                                         staticInitializerScope.problemReporter().initializerMustCompleteNormally(
220                                                                 fields[i]);
221                                                         staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
222                                                 }
223                                         } else {
224                                                 nonStaticFieldInfo =
225                                                         fields[i].analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
226                                                 // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
227                                                 // branch, since the previous initializer already got the blame.
228                                                 if (nonStaticFieldInfo == FlowInfo.DeadEnd) {
229                                                         initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
230                                                         nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
231                                                 }
232                                         }
233                                 }
234                         }
235                         if (memberTypes != null) {
236                                 for (int i = 0, count = memberTypes.length; i < count; i++) {
237                                         memberTypes[i].analyseCode(scope);
238                                 }
239                         }
240                         if (methods != null) {
241                                 int recursionBalance = 0; // check constructor recursions
242                                 for (int i = 0, count = methods.length; i < count; i++) {
243                                         AbstractMethodDeclaration method = methods[i];
244                                         if (method.ignoreFurtherInvestigation)
245                                                 continue;
246                                         if (method.isInitializationMethod()) {
247                                                 if (method.isStatic()) { // <clinit>
248                                                         ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo);
249                                                 } else { // constructor
250                                                         ConstructorDeclaration constructor = (ConstructorDeclaration) method;
251                                                         constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy());
252                                                         // compute the recursive invocation balance:
253                                                         //   how many thisReferences vs. superReferences to constructors
254                                                         int refCount;
255                                                         if ((refCount = constructor.referenceCount) > 0) {
256                                                                 if ((constructor.constructorCall == null)
257                                                                         || constructor.constructorCall.isSuperAccess()
258                                                                         || !constructor.constructorCall.binding.isValidBinding()) {
259                                                                         recursionBalance -= refCount;
260                                                                         constructor.referenceCount = -1; // for error reporting propagation                                                             
261                                                                 } else {
262                                                                         recursionBalance += refCount;
263                                                                 }
264                                                         }
265                                                 }
266                                         } else { // regular method
267                                                 method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
268                                         }
269                                 }
270                                 if (recursionBalance > 0) {
271                                         // there is one or more cycle(s) amongst constructor invocations
272                                         scope.problemReporter().recursiveConstructorInvocation(this);
273                                 }
274                         }
275                 } catch (AbortType e) {
276                         this.ignoreFurtherInvestigation = true;
277                 };
278         }
279
280         /**
281          *      Flow analysis for a local member innertype
282          *
283          */
284         public void analyseCode(
285                 ClassScope currentScope,
286                 FlowContext flowContext,
287                 FlowInfo flowInfo) {
288
289                 if (ignoreFurtherInvestigation)
290                         return;
291                 try {
292                         // remember local types binding for innerclass emulation propagation
293                         currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
294
295                         /* force to emulation of access to direct enclosing instance: only for local members.
296                          * By using the initializer scope, we actually only request an argument emulation, the
297                          * field is not added until actually used. However we will force allocations to be qualified
298                          * with an enclosing instance.
299                          */
300                         initializerScope.emulateOuterAccess(
301                                 (SourceTypeBinding) binding.enclosingType(),
302                                 false);
303
304                         InitializationFlowContext initializerContext =
305                                 new InitializationFlowContext(null, this, initializerScope);
306                         // propagate down the max field count
307                         updateMaxFieldCount();
308                         FlowInfo fieldInfo = flowInfo.copy();
309                         // so as not to propagate changes outside this type
310                         if (fields != null) {
311                                 for (int i = 0, count = fields.length; i < count; i++) {
312                                         if (!fields[i].isStatic()) {
313                                                 fieldInfo =
314                                                         fields[i].analyseCode(initializerScope, initializerContext, fieldInfo);
315                                                 if (fieldInfo == FlowInfo.DeadEnd) {
316                                                         // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
317                                                         // branch, since the previous initializer already got the blame.
318                                                         initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
319                                                         fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
320                                                 }
321                                         }
322                                 }
323                         }
324                         if (memberTypes != null) {
325                                 for (int i = 0, count = memberTypes.length; i < count; i++) {
326                                         memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
327                                 }
328                         }
329                         if (methods != null) {
330                                 int recursionBalance = 0; // check constructor recursions                       
331                                 for (int i = 0, count = methods.length; i < count; i++) {
332                                         AbstractMethodDeclaration method = methods[i];
333                                         if (method.ignoreFurtherInvestigation)
334                                                 continue;
335                                         if (method.isConstructor()) { // constructor
336                                                 ConstructorDeclaration constructor = (ConstructorDeclaration) method;
337                                                 constructor.analyseCode(scope, initializerContext, fieldInfo.copy());
338                                                 // compute the recursive invocation balance:
339                                                 //   how many thisReferences vs. superReferences to constructors
340                                                 int refCount;
341                                                 if ((refCount = constructor.referenceCount) > 0) {
342                                                         if ((constructor.constructorCall == null)
343                                                                 || constructor.constructorCall.isSuperAccess()
344                                                                 || !constructor.constructorCall.binding.isValidBinding()) {
345                                                                 recursionBalance -= refCount;
346                                                                 constructor.referenceCount = -1; // for error reporting propagation                                                             
347                                                         } else {
348                                                                 recursionBalance += refCount;
349                                                         }
350                                                 }
351                                         } else { // regular method
352                                                 method.analyseCode(scope, null, flowInfo.copy());
353                                         }
354                                 }
355                                 if (recursionBalance > 0) {
356                                         // there is one or more cycle(s) amongst constructor invocations
357                                         scope.problemReporter().recursiveConstructorInvocation(this);
358                                 }
359                         }
360                 } catch (AbortType e) {
361                         this.ignoreFurtherInvestigation = true;
362                 };
363         }
364
365         /**
366          *      Flow analysis for a package member type
367          *
368          */
369         public void analyseCode(CompilationUnitScope unitScope) {
370
371                 if (ignoreFurtherInvestigation)
372                         return;
373                 try {
374                         FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info
375                         InitializationFlowContext initializerContext =
376                                 new InitializationFlowContext(null, this, initializerScope);
377                         InitializationFlowContext staticInitializerContext =
378                                 new InitializationFlowContext(null, this, staticInitializerScope);
379                         FlowInfo nonStaticFieldInfo = flowInfo.copy(),
380                                 staticFieldInfo = flowInfo.copy();
381                         if (fields != null) {
382                                 for (int i = 0, count = fields.length; i < count; i++) {
383                                         if (fields[i].isStatic()) {
384                                                 staticFieldInfo =
385                                                         fields[i].analyseCode(
386                                                                 staticInitializerScope,
387                                                                 staticInitializerContext,
388                                                                 staticFieldInfo);
389                                                 // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
390                                                 // branch, since the previous initializer already got the blame.
391                                                 if (staticFieldInfo == FlowInfo.DeadEnd) {
392                                                         staticInitializerScope.problemReporter().initializerMustCompleteNormally(
393                                                                 fields[i]);
394                                                         staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
395                                                 }
396                                         } else {
397                                                 nonStaticFieldInfo =
398                                                         fields[i].analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
399                                                 // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
400                                                 // branch, since the previous initializer already got the blame.
401                                                 if (nonStaticFieldInfo == FlowInfo.DeadEnd) {
402                                                         initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]);
403                                                         nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
404                                                 }
405                                         }
406                                 }
407                         }
408                         if (memberTypes != null) {
409                                 for (int i = 0, count = memberTypes.length; i < count; i++) {
410                                         memberTypes[i].analyseCode(scope);
411                                 }
412                         }
413                         if (methods != null) {
414                                 int recursionBalance = 0; // check constructor recursions                       
415                                 for (int i = 0, count = methods.length; i < count; i++) {
416                                         AbstractMethodDeclaration method = methods[i];
417                                         if (method.ignoreFurtherInvestigation)
418                                                 continue;
419                                         if (method.isInitializationMethod()) {
420                                                 if (method.isStatic()) { // <clinit>
421                                                         ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo);
422                                                 } else { // constructor
423                                                         ConstructorDeclaration constructor = (ConstructorDeclaration) method;
424                                                         constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy());
425                                                         // compute the recursive invocation balance:
426                                                         //   how many thisReferences vs. superReferences to constructors
427                                                         int refCount;
428                                                         if ((refCount = constructor.referenceCount) > 0) {
429                                                                 if ((constructor.constructorCall == null)
430                                                                         || constructor.constructorCall.isSuperAccess()
431                                                                         || !constructor.constructorCall.binding.isValidBinding()) {
432                                                                         recursionBalance -= refCount;
433                                                                         constructor.referenceCount = -1; // for error reporting propagation
434                                                                 } else {
435                                                                         recursionBalance += refCount;
436                                                                 }
437                                                         }
438                                                 }
439                                         } else { // regular method
440                                                 method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
441                                         }
442                                 }
443                                 if (recursionBalance > 0) {
444                                         // there is one or more cycle(s) amongst constructor invocations
445                                         scope.problemReporter().recursiveConstructorInvocation(this);
446                                 }
447                         }
448                 } catch (AbortType e) {
449                         this.ignoreFurtherInvestigation = true;
450                 };
451         }
452
453         /*
454          * Check for constructor vs. method with no return type.
455          * Answers true if at least one constructor is defined
456          */
457         public boolean checkConstructors(Parser parser) {
458
459                 //if a constructor has not the name of the type,
460                 //convert it into a method with 'null' as its return type
461                 boolean hasConstructor = false;
462                 if (methods != null) {
463                         for (int i = methods.length; --i >= 0;) {
464                                 AbstractMethodDeclaration am;
465                                 if ((am = methods[i]).isConstructor()) {
466                                         if (!CharOperation.equals(am.selector, name)) {
467                                                 // the constructor was in fact a method with no return type
468                                                 // unless an explicit constructor call was supplied
469                                                 ConstructorDeclaration c = (ConstructorDeclaration) am;
470                                                 if ((c.constructorCall == null)
471                                                         || (c.constructorCall.isImplicitSuper())) { //changed to a method
472                                                         MethodDeclaration m = new MethodDeclaration(this.compilationResult);
473                                                         m.sourceStart = c.sourceStart;
474                                                         m.sourceEnd = c.sourceEnd;
475                                                         m.bodyStart = c.bodyStart;
476                                                         m.bodyEnd = c.bodyEnd;
477                                                         m.declarationSourceEnd = c.declarationSourceEnd;
478                                                         m.declarationSourceStart = c.declarationSourceStart;
479                                                         m.selector = c.selector;
480                                                         m.statements = c.statements;
481                                                         m.modifiers = c.modifiers;
482                                                         m.arguments = c.arguments;
483                                                         m.thrownExceptions = c.thrownExceptions;
484                                                         m.explicitDeclarations = c.explicitDeclarations;
485                                                         m.returnType = null;
486                                                         methods[i] = m;
487                                                 }
488                                         } else {
489                                                 if (this.isInterface()) {
490                                                         // report the problem and continue the parsing
491                                                         parser.problemReporter().interfaceCannotHaveConstructors(
492                                                                 (ConstructorDeclaration) am);
493                                                 }
494                                                 hasConstructor = true;
495                                         }
496                                 }
497                         }
498                 }
499                 return hasConstructor;
500         }
501
502         public CompilationResult compilationResult() {
503
504                 return this.compilationResult;
505         }
506
507         public ConstructorDeclaration createsInternalConstructor(
508                 boolean needExplicitConstructorCall,
509                 boolean needToInsert) {
510
511                 //Add to method'set, the default constuctor that just recall the
512                 //super constructor with no arguments
513                 //The arguments' type will be positionned by the TC so just use
514                 //the default int instead of just null (consistency purpose)
515
516                 //the constructor
517                 ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult);
518                 constructor.isDefaultConstructor = true;
519                 constructor.selector = name;
520                 if (modifiers != AccDefault) {
521                         constructor.modifiers =
522                                 ((this instanceof MemberTypeDeclaration) && (modifiers & AccPrivate) != 0)
523                                         ? AccDefault
524                                         : modifiers & AccVisibilityMASK;
525                 }
526
527                 //if you change this setting, please update the 
528                 //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method
529                 constructor.declarationSourceStart = constructor.sourceStart = sourceStart;
530                 constructor.declarationSourceEnd =
531                         constructor.sourceEnd = constructor.bodyEnd = sourceEnd;
532
533                 //the super call inside the constructor
534                 if (needExplicitConstructorCall) {
535                         constructor.constructorCall =
536                                 new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
537                         constructor.constructorCall.sourceStart = sourceStart;
538                         constructor.constructorCall.sourceEnd = sourceEnd;
539                 }
540
541                 //adding the constructor in the methods list
542                 if (needToInsert) {
543                         if (methods == null) {
544                                 methods = new AbstractMethodDeclaration[] { constructor };
545                         } else {
546                                 AbstractMethodDeclaration[] newMethods;
547                                 System.arraycopy(
548                                         methods,
549                                         0,
550                                         newMethods = new AbstractMethodDeclaration[methods.length + 1],
551                                         1,
552                                         methods.length);
553                                 newMethods[0] = constructor;
554                                 methods = newMethods;
555                         }
556                 }
557                 return constructor;
558         }
559
560         /**
561          * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding.
562          * It is used to report errors for missing abstract methods.
563          */
564         public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) {
565                 TypeBinding[] argumentTypes = methodBinding.parameters;
566                 int argumentsLength = argumentTypes.length;
567                 //the constructor
568                 MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult);
569                 methodDeclaration.selector = methodBinding.selector;
570                 methodDeclaration.sourceStart = sourceStart;
571                 methodDeclaration.sourceEnd = sourceEnd;
572                 methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract;
573
574                 if (argumentsLength > 0) {
575                         String baseName = "arg";//$NON-NLS-1$
576                         Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]);
577                         for (int i = argumentsLength; --i >= 0;) {
578                                 arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault);
579                         }
580                 }
581
582                 //adding the constructor in the methods list
583                 if (this.missingAbstractMethods == null) {
584                         this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration };
585                 } else {
586                         MethodDeclaration[] newMethods;
587                         System.arraycopy(
588                                 this.missingAbstractMethods,
589                                 0,
590                                 newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1],
591                                 1,
592                                 this.missingAbstractMethods.length);
593                         newMethods[0] = methodDeclaration;
594                         this.missingAbstractMethods = newMethods;
595                 }
596
597                 //============BINDING UPDATE==========================
598                 methodDeclaration.binding = new MethodBinding(
599                                 methodDeclaration.modifiers, //methodDeclaration
600                                 methodBinding.selector,
601                                 methodBinding.returnType,
602                                 argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
603                                 methodBinding.thrownExceptions, //exceptions
604                                 binding); //declaringClass
605                                 
606                 methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true);
607                 methodDeclaration.bindArguments();
608
609 /*              if (binding.methods == null) {
610                         binding.methods = new MethodBinding[] { methodDeclaration.binding };
611                 } else {
612                         MethodBinding[] newMethods;
613                         System.arraycopy(
614                                 binding.methods,
615                                 0,
616                                 newMethods = new MethodBinding[binding.methods.length + 1],
617                                 1,
618                                 binding.methods.length);
619                         newMethods[0] = methodDeclaration.binding;
620                         binding.methods = newMethods;
621                 }*/
622                 //===================================================
623
624                 return methodDeclaration;
625         }
626         
627         /*
628          * Find the matching parse node, answers null if nothing found
629          */
630         public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
631
632                 if (fieldBinding != null) {
633                         for (int i = 0, max = this.fields.length; i < max; i++) {
634                                 FieldDeclaration fieldDecl;
635                                 if ((fieldDecl = this.fields[i]).binding == fieldBinding)
636                                         return fieldDecl;
637                         }
638                 }
639                 return null;
640         }
641
642         /*
643          * Find the matching parse node, answers null if nothing found
644          */
645         public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
646
647                 if (memberTypeBinding != null) {
648                         for (int i = 0, max = this.memberTypes.length; i < max; i++) {
649                                 TypeDeclaration memberTypeDecl;
650                                 if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding)
651                                         return memberTypeDecl;
652                         }
653                 }
654                 return null;
655         }
656
657         /*
658          * Find the matching parse node, answers null if nothing found
659          */
660         public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
661
662                 if (methodBinding != null) {
663                         for (int i = 0, max = this.methods.length; i < max; i++) {
664                                 AbstractMethodDeclaration methodDecl;
665
666                                 if ((methodDecl = this.methods[i]).binding == methodBinding)
667                                         return methodDecl;
668                         }
669                 }
670                 return null;
671         }
672
673         /*
674          * Finds the matching type amoung this type's member types.
675          * Returns null if no type with this name is found.
676          * The type name is a compound name relative to this type
677          * eg. if this type is X and we're looking for Y.X.A.B
678          *     then a type name would be {X, A, B}
679          */
680         public TypeDeclaration declarationOfType(char[][] typeName) {
681
682                 int typeNameLength = typeName.length;
683                 if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
684                         return null;
685                 }
686                 if (typeNameLength == 1) {
687                         return this;
688                 }
689                 char[][] subTypeName = new char[typeNameLength - 1][];
690                 System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1);
691                 for (int i = 0; i < this.memberTypes.length; i++) {
692                         TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName);
693                         if (typeDecl != null) {
694                                 return typeDecl;
695                         }
696                 }
697                 return null;
698         }
699
700         /**
701          * Generic bytecode generation for type
702          */
703         public void generateCode(ClassFile enclosingClassFile) {
704
705                 if (hasBeenGenerated)
706                         return;
707                 hasBeenGenerated = true;
708                 if (ignoreFurtherInvestigation) {
709                         if (binding == null)
710                                 return;
711                         ClassFile.createProblemType(
712                                 this,
713                                 scope.referenceCompilationUnit().compilationResult);
714                         return;
715                 }
716                 try {
717                         // create the result for a compiled type
718                         ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
719                         // generate all fiels
720                         classFile.addFieldInfos();
721
722                         // record the inner type inside its own .class file to be able
723                         // to generate inner classes attributes
724                         if (binding.isMemberType())
725                                 classFile.recordEnclosingTypeAttributes(binding);
726                         if (binding.isLocalType()) {
727                                 enclosingClassFile.recordNestedLocalAttribute(binding);
728                                 classFile.recordNestedLocalAttribute(binding);
729                         }
730                         if (memberTypes != null) {
731                                 for (int i = 0, max = memberTypes.length; i < max; i++) {
732                                         // record the inner type inside its own .class file to be able
733                                         // to generate inner classes attributes
734                                         classFile.recordNestedMemberAttribute(memberTypes[i].binding);
735                                         memberTypes[i].generateCode(scope, classFile);
736                                 }
737                         }
738                         // generate all methods
739                         classFile.setForMethodInfos();
740                         if (methods != null) {
741                                 for (int i = 0, max = methods.length; i < max; i++) {
742                                         methods[i].generateCode(scope, classFile);
743                                 }
744                         }
745                         
746                         classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult);
747
748                         // generate all methods
749                         classFile.addSpecialMethods();
750
751                         if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
752                                 throw new AbortType(scope.referenceCompilationUnit().compilationResult);
753                         }
754
755                         // finalize the compiled type result
756                         classFile.addAttributes();
757                         scope.referenceCompilationUnit().compilationResult.record(
758                                 binding.constantPoolName(),
759                                 classFile);
760                 } catch (AbortType e) {
761                         if (binding == null)
762                                 return;
763                         ClassFile.createProblemType(
764                                 this,
765                                 scope.referenceCompilationUnit().compilationResult);
766                 }
767         }
768
769         /**
770          * Bytecode generation for a local inner type (API as a normal statement code gen)
771          */
772         public void generateCode(BlockScope blockScope, CodeStream codeStream) {
773
774                 if (hasBeenGenerated)
775                         return;
776                 int pc = codeStream.position;
777                 if (binding != null) {
778                         ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
779                 }
780                 generateCode(codeStream.classFile);
781                 codeStream.recordPositionsFrom(pc, this.sourceStart);
782         }
783
784         /**
785          * Bytecode generation for a member inner type
786          */
787         public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
788
789                 if (hasBeenGenerated)
790                         return;
791                 ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
792                 generateCode(enclosingClassFile);
793         }
794
795         /**
796          * Bytecode generation for a package member
797          */
798         public void generateCode(CompilationUnitScope unitScope) {
799
800                 generateCode((ClassFile) null);
801         }
802
803         public boolean isInterface() {
804
805                 return (modifiers & AccInterface) != 0;
806         }
807
808         public boolean hasErrors() {
809                 return this.ignoreFurtherInvestigation;
810         }
811
812         /**
813          * A <clinit> will be requested as soon as static fields or assertions are present. It will be eliminated during
814          * classfile creation if no bytecode was actually produced based on some optimizations/compiler settings.
815          */
816         public final boolean needClassInitMethod() {
817
818                 // always need a <clinit> when assertions are present
819                 if ((this.bits & AddAssertionMASK) != 0)
820                         return true;
821                 if (fields == null)
822                         return false;
823                 if (isInterface())
824                         return true; // fields are implicitly statics
825                 for (int i = fields.length; --i >= 0;) {
826                         FieldDeclaration field = fields[i];
827                         //need to test the modifier directly while there is no binding yet
828                         if ((field.modifiers & AccStatic) != 0)
829                                 return true;
830                 }
831                 return false;
832         }
833
834         public void parseMethod(Parser parser, CompilationUnitDeclaration unit) {
835
836                 //connect method bodies
837                 if (unit.ignoreMethodBodies)
838                         return;
839
840                 // no scope were created, so cannot report further errors
841 //              if (binding == null)
842 //                      return;
843
844                 //members
845                 if (memberTypes != null) {
846                         for (int i = memberTypes.length; --i >= 0;)
847                                 memberTypes[i].parseMethod(parser, unit);
848                 }
849
850                 //methods
851                 if (methods != null) {
852                         for (int i = methods.length; --i >= 0;)
853                                 methods[i].parseStatements(parser, unit);
854                 }
855
856                 //initializers
857                 if (fields != null) {
858                         for (int i = fields.length; --i >= 0;) {
859                                 if (fields[i] instanceof Initializer) {
860                                         ((Initializer) fields[i]).parseStatements(parser, this, unit);
861                                 }
862                         }
863                 }
864         }
865
866         public void resolve() {
867
868                 if (binding == null) {
869                         ignoreFurtherInvestigation = true;
870                         return;
871                 }
872
873                 try {
874                         // check superclass & interfaces
875                         if (binding.superclass != null) // watch out for Object ! (and other roots)     
876                                 if (isTypeUseDeprecated(binding.superclass, scope))
877                                         scope.problemReporter().deprecatedType(binding.superclass, superclass);
878                         if (superInterfaces != null)
879                                 for (int i = superInterfaces.length; --i >= 0;)
880                                         if (superInterfaces[i].binding != null)
881                                                 if (isTypeUseDeprecated(superInterfaces[i].binding, scope))
882                                                         scope.problemReporter().deprecatedType(
883                                                                 superInterfaces[i].binding,
884                                                                 superInterfaces[i]);
885                         maxFieldCount = 0;
886                         int lastFieldID = -1;
887                         if (fields != null) {
888                                 for (int i = 0, count = fields.length; i < count; i++) {
889                                         FieldDeclaration field = fields[i];
890                                         if (field.isField()) {
891                                                 if (field.binding == null) {
892                                                         ignoreFurtherInvestigation = true;
893                                                         continue;
894                                                 }
895                                                 maxFieldCount++;
896                                                 lastFieldID = field.binding.id;
897                                         } else { // initializer
898                                                  ((Initializer) field).lastFieldID = lastFieldID + 1;
899                                         }
900                                         field.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
901                                 }
902                         }
903                         if (memberTypes != null)
904                                 for (int i = 0, count = memberTypes.length; i < count; i++)
905                                         memberTypes[i].resolve(scope);
906                         if (methods != null)
907                                 for (int i = 0, count = methods.length; i < count; i++)
908                                         methods[i].resolve(scope);
909                 } catch (AbortType e) {
910                         this.ignoreFurtherInvestigation = true;
911                         return;
912                 };
913         }
914
915         public void resolve(BlockScope blockScope) {
916                 // local type declaration
917
918                 // need to build its scope first and proceed with binding's creation
919                 blockScope.addLocalType(this);
920
921                 // and TC....
922                 if (binding != null) {
923                         // binding is not set if the receiver could not be created
924                         resolve();
925                         updateMaxFieldCount();
926                 }
927         }
928
929         public void resolve(ClassScope upperScope) {
930                 // member scopes are already created
931                 // request the construction of a binding if local member type
932
933                 resolve();
934                 updateMaxFieldCount();
935         }
936
937         public void resolve(CompilationUnitScope upperScope) {
938                 // top level : scope are already created
939
940                 resolve();
941                 updateMaxFieldCount();
942         }
943
944         public void tagAsHavingErrors() {
945                 ignoreFurtherInvestigation = true;
946         }
947
948         public String toString(int tab) {
949
950                 return tabString(tab) + toStringHeader() + toStringBody(tab);
951         }
952
953         public String toStringBody(int tab) {
954
955                 String s = " {"; //$NON-NLS-1$
956                 if (memberTypes != null) {
957                         for (int i = 0; i < memberTypes.length; i++) {
958                                 if (memberTypes[i] != null) {
959                                         s += "\n" + memberTypes[i].toString(tab + 1); //$NON-NLS-1$
960                                 }
961                         }
962                 }
963                 if (fields != null) {
964                         for (int fieldI = 0; fieldI < fields.length; fieldI++) {
965                                 if (fields[fieldI] != null) {
966                                         s += "\n" + fields[fieldI].toString(tab + 1); //$NON-NLS-1$
967                                         if (fields[fieldI].isField())
968                                                 s += ";"; //$NON-NLS-1$
969                                 }
970                         }
971                 }
972                 if (methods != null) {
973                         for (int i = 0; i < methods.length; i++) {
974                                 if (methods[i] != null) {
975                                         s += "\n" + methods[i].toString(tab + 1); //$NON-NLS-1$
976                                 }
977                         }
978                 }
979                 s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
980                 return s;
981         }
982
983         public String toStringHeader() {
984
985                 String s = ""; //$NON-NLS-1$
986                 if (modifiers != AccDefault) {
987                         s += modifiersString(modifiers);
988                 }
989                 s += (isInterface() ? "interface " : "class ") + new String(name);//$NON-NLS-1$ //$NON-NLS-2$
990                 if (superclass != null)
991                         s += " extends " + superclass.toString(0); //$NON-NLS-1$
992                 if (superInterfaces != null && superInterfaces.length > 0) {
993                         s += (isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$
994                         for (int i = 0; i < superInterfaces.length; i++) {
995                                 s += superInterfaces[i].toString(0);
996                                 if (i != superInterfaces.length - 1)
997                                         s += ", "; //$NON-NLS-1$
998                         };
999                 };
1000                 return s;
1001         }
1002
1003         /**
1004          *      Iteration for a package member type
1005          *
1006          */
1007         public void traverse(
1008                 IAbstractSyntaxTreeVisitor visitor,
1009                 CompilationUnitScope unitScope) {
1010
1011                 if (ignoreFurtherInvestigation)
1012                         return;
1013                 try {
1014                         if (visitor.visit(this, unitScope)) {
1015                                 if (superclass != null)
1016                                         superclass.traverse(visitor, scope);
1017                                 if (superInterfaces != null) {
1018                                         int superInterfaceLength = superInterfaces.length;
1019                                         for (int i = 0; i < superInterfaceLength; i++)
1020                                                 superInterfaces[i].traverse(visitor, scope);
1021                                 }
1022                                 if (memberTypes != null) {
1023                                         int memberTypesLength = memberTypes.length;
1024                                         for (int i = 0; i < memberTypesLength; i++)
1025                                                 memberTypes[i].traverse(visitor, scope);
1026                                 }
1027                                 if (fields != null) {
1028                                         int fieldsLength = fields.length;
1029                                         for (int i = 0; i < fieldsLength; i++) {
1030                                                 FieldDeclaration field;
1031                                                 if ((field = fields[i]).isStatic()) {
1032                                                         field.traverse(visitor, staticInitializerScope);
1033                                                 } else {
1034                                                         field.traverse(visitor, initializerScope);
1035                                                 }
1036                                         }
1037                                 }
1038                                 if (methods != null) {
1039                                         int methodsLength = methods.length;
1040                                         for (int i = 0; i < methodsLength; i++)
1041                                                 methods[i].traverse(visitor, scope);
1042                                 }
1043                         }
1044                 } catch (AbortType e) {
1045                 }
1046         }
1047
1048         /**
1049          * MaxFieldCount's computation is necessary so as to reserve space for
1050          * the flow info field portions. It corresponds to the maximum amount of
1051          * fields this class or one of its innertypes have.
1052          *
1053          * During name resolution, types are traversed, and the max field count is recorded
1054          * on the outermost type. It is then propagated down during the flow analysis.
1055          *
1056          * This method is doing either up/down propagation.
1057          */
1058         void updateMaxFieldCount() {
1059
1060                 if (binding == null)
1061                         return; // error scenario
1062                 TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
1063                 if (maxFieldCount > outerMostType.maxFieldCount) {
1064                         outerMostType.maxFieldCount = maxFieldCount; // up
1065                 } else {
1066                         maxFieldCount = outerMostType.maxFieldCount; // down
1067                 }
1068         }
1069 }