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.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;
40 public class TypeDeclaration
42 implements ProblemSeverities, ReferenceContext {
45 public int modifiersSourceStart;
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;
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;
66 public TypeDeclaration(CompilationResult compilationResult){
67 this.compilationResult = compilationResult;
71 * We cause the compilation task to abort to a given extent.
73 public void abort(int abortLevel) {
76 throw new AbortCompilation(); // cannot do better
79 CompilationResult compilationResult =
80 scope.referenceCompilationUnit().compilationResult;
83 case AbortCompilation :
84 throw new AbortCompilation(compilationResult);
85 case AbortCompilationUnit :
86 throw new AbortCompilationUnit(compilationResult);
88 throw new AbortMethod(compilationResult);
90 throw new AbortType(compilationResult);
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.
101 * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int)
103 public final void addClinit() {
105 //see comment on needClassInitMethod
106 if (needClassInitMethod()) {
108 AbstractMethodDeclaration[] methods;
109 if ((methods = this.methods) == null) {
111 methods = new AbstractMethodDeclaration[1];
113 length = methods.length;
117 (methods = new AbstractMethodDeclaration[length + 1]),
121 Clinit clinit = new Clinit(this.compilationResult);
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;
132 * Flow analysis for a local innertype
135 public FlowInfo analyseCode(
136 BlockScope currentScope,
137 FlowContext flowContext,
140 if (ignoreFurtherInvestigation)
143 // remember local types binding for innerclass emulation propagation
144 currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
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++) {
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);
164 if (memberTypes != null) {
165 for (int i = 0, count = memberTypes.length; i < count; i++) {
166 memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
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)
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
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
189 recursionBalance += refCount;
192 } else { // regular method
193 method.analyseCode(scope, null, flowInfo.copy());
196 if (recursionBalance > 0) {
197 // there is one or more cycle(s) amongst constructor invocations
198 scope.problemReporter().recursiveConstructorInvocation(this);
201 } catch (AbortType e) {
202 this.ignoreFurtherInvestigation = true;
208 * Flow analysis for a member innertype
211 public void analyseCode(ClassScope classScope1) {
213 if (ignoreFurtherInvestigation)
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()) {
229 fields[i].analyseCode(
230 staticInitializerScope,
231 staticInitializerContext,
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(
238 staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
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);
252 if (memberTypes != null) {
253 for (int i = 0, count = memberTypes.length; i < count; i++) {
254 memberTypes[i].analyseCode(scope);
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)
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
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
279 recursionBalance += refCount;
283 } else { // regular method
284 method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
287 if (recursionBalance > 0) {
288 // there is one or more cycle(s) amongst constructor invocations
289 scope.problemReporter().recursiveConstructorInvocation(this);
292 } catch (AbortType e) {
293 this.ignoreFurtherInvestigation = true;
298 * Flow analysis for a local member innertype
301 public void analyseCode(
302 ClassScope currentScope,
303 FlowContext flowContext,
306 if (ignoreFurtherInvestigation)
309 // remember local types binding for innerclass emulation propagation
310 currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
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.
317 initializerScope.emulateOuterAccess(
318 (SourceTypeBinding) binding.enclosingType(),
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()) {
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);
341 if (memberTypes != null) {
342 for (int i = 0, count = memberTypes.length; i < count; i++) {
343 memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy());
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)
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
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
365 recursionBalance += refCount;
368 } else { // regular method
369 method.analyseCode(scope, null, flowInfo.copy());
372 if (recursionBalance > 0) {
373 // there is one or more cycle(s) amongst constructor invocations
374 scope.problemReporter().recursiveConstructorInvocation(this);
377 } catch (AbortType e) {
378 this.ignoreFurtherInvestigation = true;
383 * Flow analysis for a package member type
386 public void analyseCode(CompilationUnitScope unitScope) {
388 if (ignoreFurtherInvestigation)
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()) {
402 fields[i].analyseCode(
403 staticInitializerScope,
404 staticInitializerContext,
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(
411 staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true);
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);
425 if (memberTypes != null) {
426 for (int i = 0, count = memberTypes.length; i < count; i++) {
427 memberTypes[i].analyseCode(scope);
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)
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
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
452 recursionBalance += refCount;
456 } else { // regular method
457 method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount));
460 if (recursionBalance > 0) {
461 // there is one or more cycle(s) amongst constructor invocations
462 scope.problemReporter().recursiveConstructorInvocation(this);
465 } catch (AbortType e) {
466 this.ignoreFurtherInvestigation = true;
471 * Check for constructor vs. method with no return type.
472 * Answers true if at least one constructor is defined
474 public boolean checkConstructors(Parser parser) {
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;
506 if (this.isInterface()) {
507 // report the problem and continue the parsing
508 parser.problemReporter().interfaceCannotHaveConstructors(
509 (ConstructorDeclaration) am);
511 hasConstructor = true;
516 return hasConstructor;
519 public CompilationResult compilationResult() {
521 return this.compilationResult;
524 public ConstructorDeclaration createsInternalConstructor(
525 boolean needExplicitConstructorCall,
526 boolean needToInsert) {
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)
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)
541 : modifiers & AccVisibilityMASK;
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;
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;
558 //adding the constructor in the methods list
560 if (methods == null) {
561 methods = new AbstractMethodDeclaration[] { constructor };
563 AbstractMethodDeclaration[] newMethods;
567 newMethods = new AbstractMethodDeclaration[methods.length + 1],
570 newMethods[0] = constructor;
571 methods = newMethods;
578 * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding.
579 * It is used to report errors for missing abstract methods.
581 public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) {
582 TypeBinding[] argumentTypes = methodBinding.parameters;
583 int argumentsLength = argumentTypes.length;
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;
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);
599 //adding the constructor in the methods list
600 if (this.missingAbstractMethods == null) {
601 this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration };
603 MethodDeclaration[] newMethods;
605 this.missingAbstractMethods,
607 newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1],
609 this.missingAbstractMethods.length);
610 newMethods[0] = methodDeclaration;
611 this.missingAbstractMethods = newMethods;
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
623 methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true);
624 methodDeclaration.bindArguments();
626 /* if (binding.methods == null) {
627 binding.methods = new MethodBinding[] { methodDeclaration.binding };
629 MethodBinding[] newMethods;
633 newMethods = new MethodBinding[binding.methods.length + 1],
635 binding.methods.length);
636 newMethods[0] = methodDeclaration.binding;
637 binding.methods = newMethods;
639 //===================================================
641 return methodDeclaration;
645 * Find the matching parse node, answers null if nothing found
647 public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
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)
660 * Find the matching parse node, answers null if nothing found
662 public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
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;
675 * Find the matching parse node, answers null if nothing found
677 public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
679 if (methodBinding != null) {
680 for (int i = 0, max = this.methods.length; i < max; i++) {
681 AbstractMethodDeclaration methodDecl;
683 if ((methodDecl = this.methods[i]).binding == methodBinding)
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}
697 public TypeDeclaration declarationOfType(char[][] typeName) {
699 int typeNameLength = typeName.length;
700 if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
703 if (typeNameLength == 1) {
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) {
718 * Generic bytecode generation for type
720 public void generateCode(ClassFile enclosingClassFile) {
722 if (hasBeenGenerated)
724 hasBeenGenerated = true;
725 if (ignoreFurtherInvestigation) {
728 ClassFile.createProblemType(
730 scope.referenceCompilationUnit().compilationResult);
734 // create the result for a compiled type
735 ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
736 // generate all fiels
737 classFile.addFieldInfos();
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);
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);
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);
763 classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult);
765 // generate all methods
766 classFile.addSpecialMethods();
768 if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
769 throw new AbortType(scope.referenceCompilationUnit().compilationResult);
772 // finalize the compiled type result
773 classFile.addAttributes();
774 scope.referenceCompilationUnit().compilationResult.record(
775 binding.constantPoolName(),
777 } catch (AbortType e) {
780 ClassFile.createProblemType(
782 scope.referenceCompilationUnit().compilationResult);
787 * Bytecode generation for a local inner type (API as a normal statement code gen)
789 public void generateCode(BlockScope blockScope, CodeStream codeStream) {
791 if (hasBeenGenerated)
793 int pc = codeStream.position;
794 if (binding != null) {
795 ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
797 generateCode(codeStream.classFile);
798 codeStream.recordPositionsFrom(pc, this.sourceStart);
802 * Bytecode generation for a member inner type
804 public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
806 if (hasBeenGenerated)
808 ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset();
809 generateCode(enclosingClassFile);
813 * Bytecode generation for a package member
815 public void generateCode(CompilationUnitScope unitScope) {
817 generateCode((ClassFile) null);
820 public boolean isInterface() {
822 return (modifiers & AccInterface) != 0;
825 public boolean hasErrors() {
826 return this.ignoreFurtherInvestigation;
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.
833 public final boolean needClassInitMethod() {
835 // always need a <clinit> when assertions are present
836 if ((this.bits & AddAssertionMASK) != 0)
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)
851 public void parseMethod(Parser parser, CompilationUnitDeclaration unit) {
853 //connect method bodies
854 if (unit.ignoreMethodBodies)
857 // no scope were created, so cannot report further errors
858 // if (binding == null)
862 if (memberTypes != null) {
863 for (int i = memberTypes.length; --i >= 0;)
864 memberTypes[i].parseMethod(parser, unit);
868 if (methods != null) {
869 for (int i = methods.length; --i >= 0;)
870 methods[i].parseStatements(parser, unit);
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);
883 public void resolve() {
885 if (binding == null) {
886 ignoreFurtherInvestigation = true;
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,
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;
913 lastFieldID = field.binding.id;
914 } else { // initializer
915 ((Initializer) field).lastFieldID = lastFieldID + 1;
917 field.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
920 if (memberTypes != null)
921 for (int i = 0, count = memberTypes.length; i < count; i++)
922 memberTypes[i].resolve(scope);
924 for (int i = 0, count = methods.length; i < count; i++)
925 methods[i].resolve(scope);
926 } catch (AbortType e) {
927 this.ignoreFurtherInvestigation = true;
932 public void resolve(BlockScope blockScope) {
933 // local type declaration
935 // need to build its scope first and proceed with binding's creation
936 blockScope.addLocalType(this);
939 if (binding != null) {
940 // binding is not set if the receiver could not be created
942 updateMaxFieldCount();
946 public void resolve(ClassScope upperScope) {
947 // member scopes are already created
948 // request the construction of a binding if local member type
951 updateMaxFieldCount();
954 public void resolve(CompilationUnitScope upperScope) {
955 // top level : scope are already created
958 updateMaxFieldCount();
961 public void tagAsHavingErrors() {
962 ignoreFurtherInvestigation = true;
965 public String toString(int tab) {
967 return tabString(tab) + toStringHeader() + toStringBody(tab);
970 public String toStringBody(int tab) {
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$
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$
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$
996 s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
1000 public String toStringHeader() {
1002 String s = ""; //$NON-NLS-1$
1003 if (modifiers != AccDefault) {
1004 s += modifiersString(modifiers);
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$
1021 * Iteration for a package member type
1024 public void traverse(
1025 IAbstractSyntaxTreeVisitor visitor,
1026 CompilationUnitScope unitScope) {
1028 if (ignoreFurtherInvestigation)
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);
1039 if (memberTypes != null) {
1040 int memberTypesLength = memberTypes.length;
1041 for (int i = 0; i < memberTypesLength; i++)
1042 memberTypes[i].traverse(visitor, scope);
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);
1051 field.traverse(visitor, initializerScope);
1055 if (methods != null) {
1056 int methodsLength = methods.length;
1057 for (int i = 0; i < methodsLength; i++)
1058 methods[i].traverse(visitor, scope);
1061 } catch (AbortType e) {
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.
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.
1073 * This method is doing either up/down propagation.
1075 void updateMaxFieldCount() {
1077 if (binding == null)
1078 return; // error scenario
1079 TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
1080 if (maxFieldCount > outerMostType.maxFieldCount) {
1081 outerMostType.maxFieldCount = maxFieldCount; // up
1083 maxFieldCount = outerMostType.maxFieldCount; // down