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