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
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
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.*;
23 public class TypeDeclaration
25 implements ProblemSeverities, ReferenceContext {
28 public int modifiersSourceStart;
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;
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;
49 public TypeDeclaration(CompilationResult compilationResult){
50 this.compilationResult = compilationResult;
54 * We cause the compilation task to abort to a given extent.
56 public void abort(int abortLevel) {
59 throw new AbortCompilation(); // cannot do better
62 CompilationResult compilationResult =
63 scope.referenceCompilationUnit().compilationResult;
66 case AbortCompilation :
67 throw new AbortCompilation(compilationResult);
68 case AbortCompilationUnit :
69 throw new AbortCompilationUnit(compilationResult);
71 throw new AbortMethod(compilationResult);
73 throw new AbortType(compilationResult);
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.
84 * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int)
86 public final void addClinit() {
88 //see comment on needClassInitMethod
89 if (needClassInitMethod()) {
91 AbstractMethodDeclaration[] methods;
92 if ((methods = this.methods) == null) {
94 methods = new AbstractMethodDeclaration[1];
96 length = methods.length;
100 (methods = new AbstractMethodDeclaration[length + 1]),
104 Clinit clinit = new Clinit(this.compilationResult);
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;
115 * Flow analysis for a local innertype
118 public FlowInfo analyseCode(
119 BlockScope currentScope,
120 FlowContext flowContext,
123 if (ignoreFurtherInvestigation)
126 // remember local types binding for innerclass emulation propagation
127 currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
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++) {
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);
147 if (memberTypes != null) {
148 for (int i = 0, count = memberTypes.length; i < count; i++) {
149 memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
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)
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
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
172 recursionBalance += refCount;
175 } else { // regular method
176 method.analyseCode(scope, null, flowInfo.copy());
179 if (recursionBalance > 0) {
180 // there is one or more cycle(s) amongst constructor invocations
181 scope.problemReporter().recursiveConstructorInvocation(this);
184 } catch (AbortType e) {
185 this.ignoreFurtherInvestigation = true;
191 * Flow analysis for a member innertype
194 public void analyseCode(ClassScope classScope1) {
196 if (ignoreFurtherInvestigation)
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()) {
212 fields[i].analyseCode(
213 staticInitializerScope,
214 staticInitializerContext,
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(
221 staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
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);
235 if (memberTypes != null) {
236 for (int i = 0, count = memberTypes.length; i < count; i++) {
237 memberTypes[i].analyseCode(scope);
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)
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
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
262 recursionBalance += refCount;
266 } else { // regular method
267 method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
270 if (recursionBalance > 0) {
271 // there is one or more cycle(s) amongst constructor invocations
272 scope.problemReporter().recursiveConstructorInvocation(this);
275 } catch (AbortType e) {
276 this.ignoreFurtherInvestigation = true;
281 * Flow analysis for a local member innertype
284 public void analyseCode(
285 ClassScope currentScope,
286 FlowContext flowContext,
289 if (ignoreFurtherInvestigation)
292 // remember local types binding for innerclass emulation propagation
293 currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
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.
300 initializerScope.emulateOuterAccess(
301 (SourceTypeBinding) binding.enclosingType(),
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()) {
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);
324 if (memberTypes != null) {
325 for (int i = 0, count = memberTypes.length; i < count; i++) {
326 memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
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)
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
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
348 recursionBalance += refCount;
351 } else { // regular method
352 method.analyseCode(scope, null, flowInfo.copy());
355 if (recursionBalance > 0) {
356 // there is one or more cycle(s) amongst constructor invocations
357 scope.problemReporter().recursiveConstructorInvocation(this);
360 } catch (AbortType e) {
361 this.ignoreFurtherInvestigation = true;
366 * Flow analysis for a package member type
369 public void analyseCode(CompilationUnitScope unitScope) {
371 if (ignoreFurtherInvestigation)
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()) {
385 fields[i].analyseCode(
386 staticInitializerScope,
387 staticInitializerContext,
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(
394 staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
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);
408 if (memberTypes != null) {
409 for (int i = 0, count = memberTypes.length; i < count; i++) {
410 memberTypes[i].analyseCode(scope);
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)
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
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
435 recursionBalance += refCount;
439 } else { // regular method
440 method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
443 if (recursionBalance > 0) {
444 // there is one or more cycle(s) amongst constructor invocations
445 scope.problemReporter().recursiveConstructorInvocation(this);
448 } catch (AbortType e) {
449 this.ignoreFurtherInvestigation = true;
454 * Check for constructor vs. method with no return type.
455 * Answers true if at least one constructor is defined
457 public boolean checkConstructors(Parser parser) {
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;
489 if (this.isInterface()) {
490 // report the problem and continue the parsing
491 parser.problemReporter().interfaceCannotHaveConstructors(
492 (ConstructorDeclaration) am);
494 hasConstructor = true;
499 return hasConstructor;
502 public CompilationResult compilationResult() {
504 return this.compilationResult;
507 public ConstructorDeclaration createsInternalConstructor(
508 boolean needExplicitConstructorCall,
509 boolean needToInsert) {
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)
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)
524 : modifiers & AccVisibilityMASK;
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;
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;
541 //adding the constructor in the methods list
543 if (methods == null) {
544 methods = new AbstractMethodDeclaration[] { constructor };
546 AbstractMethodDeclaration[] newMethods;
550 newMethods = new AbstractMethodDeclaration[methods.length + 1],
553 newMethods[0] = constructor;
554 methods = newMethods;
561 * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding.
562 * It is used to report errors for missing abstract methods.
564 public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) {
565 TypeBinding[] argumentTypes = methodBinding.parameters;
566 int argumentsLength = argumentTypes.length;
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;
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);
582 //adding the constructor in the methods list
583 if (this.missingAbstractMethods == null) {
584 this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration };
586 MethodDeclaration[] newMethods;
588 this.missingAbstractMethods,
590 newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1],
592 this.missingAbstractMethods.length);
593 newMethods[0] = methodDeclaration;
594 this.missingAbstractMethods = newMethods;
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
606 methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true);
607 methodDeclaration.bindArguments();
609 /* if (binding.methods == null) {
610 binding.methods = new MethodBinding[] { methodDeclaration.binding };
612 MethodBinding[] newMethods;
616 newMethods = new MethodBinding[binding.methods.length + 1],
618 binding.methods.length);
619 newMethods[0] = methodDeclaration.binding;
620 binding.methods = newMethods;
622 //===================================================
624 return methodDeclaration;
628 * Find the matching parse node, answers null if nothing found
630 public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
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)
643 * Find the matching parse node, answers null if nothing found
645 public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
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;
658 * Find the matching parse node, answers null if nothing found
660 public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
662 if (methodBinding != null) {
663 for (int i = 0, max = this.methods.length; i < max; i++) {
664 AbstractMethodDeclaration methodDecl;
666 if ((methodDecl = this.methods[i]).binding == methodBinding)
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}
680 public TypeDeclaration declarationOfType(char[][] typeName) {
682 int typeNameLength = typeName.length;
683 if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
686 if (typeNameLength == 1) {
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) {
701 * Generic bytecode generation for type
703 public void generateCode(ClassFile enclosingClassFile) {
705 if (hasBeenGenerated)
707 hasBeenGenerated = true;
708 if (ignoreFurtherInvestigation) {
711 ClassFile.createProblemType(
713 scope.referenceCompilationUnit().compilationResult);
717 // create the result for a compiled type
718 ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
719 // generate all fiels
720 classFile.addFieldInfos();
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);
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);
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);
746 classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult);
748 // generate all methods
749 classFile.addSpecialMethods();
751 if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
752 throw new AbortType(scope.referenceCompilationUnit().compilationResult);
755 // finalize the compiled type result
756 classFile.addAttributes();
757 scope.referenceCompilationUnit().compilationResult.record(
758 binding.constantPoolName(),
760 } catch (AbortType e) {
763 ClassFile.createProblemType(
765 scope.referenceCompilationUnit().compilationResult);
770 * Bytecode generation for a local inner type (API as a normal statement code gen)
772 public void generateCode(BlockScope blockScope, CodeStream codeStream) {
774 if (hasBeenGenerated)
776 int pc = codeStream.position;
777 if (binding != null) {
778 ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
780 generateCode(codeStream.classFile);
781 codeStream.recordPositionsFrom(pc, this.sourceStart);
785 * Bytecode generation for a member inner type
787 public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
789 if (hasBeenGenerated)
791 ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
792 generateCode(enclosingClassFile);
796 * Bytecode generation for a package member
798 public void generateCode(CompilationUnitScope unitScope) {
800 generateCode((ClassFile) null);
803 public boolean isInterface() {
805 return (modifiers & AccInterface) != 0;
808 public boolean hasErrors() {
809 return this.ignoreFurtherInvestigation;
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.
816 public final boolean needClassInitMethod() {
818 // always need a <clinit> when assertions are present
819 if ((this.bits & AddAssertionMASK) != 0)
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)
834 public void parseMethod(Parser parser, CompilationUnitDeclaration unit) {
836 //connect method bodies
837 if (unit.ignoreMethodBodies)
840 // no scope were created, so cannot report further errors
841 // if (binding == null)
845 if (memberTypes != null) {
846 for (int i = memberTypes.length; --i >= 0;)
847 memberTypes[i].parseMethod(parser, unit);
851 if (methods != null) {
852 for (int i = methods.length; --i >= 0;)
853 methods[i].parseStatements(parser, unit);
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);
866 public void resolve() {
868 if (binding == null) {
869 ignoreFurtherInvestigation = true;
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,
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;
896 lastFieldID = field.binding.id;
897 } else { // initializer
898 ((Initializer) field).lastFieldID = lastFieldID + 1;
900 field.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
903 if (memberTypes != null)
904 for (int i = 0, count = memberTypes.length; i < count; i++)
905 memberTypes[i].resolve(scope);
907 for (int i = 0, count = methods.length; i < count; i++)
908 methods[i].resolve(scope);
909 } catch (AbortType e) {
910 this.ignoreFurtherInvestigation = true;
915 public void resolve(BlockScope blockScope) {
916 // local type declaration
918 // need to build its scope first and proceed with binding's creation
919 blockScope.addLocalType(this);
922 if (binding != null) {
923 // binding is not set if the receiver could not be created
925 updateMaxFieldCount();
929 public void resolve(ClassScope upperScope) {
930 // member scopes are already created
931 // request the construction of a binding if local member type
934 updateMaxFieldCount();
937 public void resolve(CompilationUnitScope upperScope) {
938 // top level : scope are already created
941 updateMaxFieldCount();
944 public void tagAsHavingErrors() {
945 ignoreFurtherInvestigation = true;
948 public String toString(int tab) {
950 return tabString(tab) + toStringHeader() + toStringBody(tab);
953 public String toStringBody(int tab) {
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$
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$
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$
979 s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
983 public String toStringHeader() {
985 String s = ""; //$NON-NLS-1$
986 if (modifiers != AccDefault) {
987 s += modifiersString(modifiers);
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$
1004 * Iteration for a package member type
1007 public void traverse(
1008 IAbstractSyntaxTreeVisitor visitor,
1009 CompilationUnitScope unitScope) {
1011 if (ignoreFurtherInvestigation)
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);
1022 if (memberTypes != null) {
1023 int memberTypesLength = memberTypes.length;
1024 for (int i = 0; i < memberTypesLength; i++)
1025 memberTypes[i].traverse(visitor, scope);
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);
1034 field.traverse(visitor, initializerScope);
1038 if (methods != null) {
1039 int methodsLength = methods.length;
1040 for (int i = 0; i < methodsLength; i++)
1041 methods[i].traverse(visitor, scope);
1044 } catch (AbortType e) {
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.
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.
1056 * This method is doing either up/down propagation.
1058 void updateMaxFieldCount() {
1060 if (binding == null)
1061 return; // error scenario
1062 TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
1063 if (maxFieldCount > outerMostType.maxFieldCount) {
1064 outerMostType.maxFieldCount = maxFieldCount; // up
1066 maxFieldCount = outerMostType.maxFieldCount; // down