1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
13 import org.eclipse.jdt.core.compiler.*;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.*;
16 import org.eclipse.jdt.internal.compiler.impl.*;
17 import org.eclipse.jdt.internal.compiler.codegen.*;
18 import org.eclipse.jdt.internal.compiler.env.IGenericType;
19 import org.eclipse.jdt.internal.compiler.flow.*;
20 import org.eclipse.jdt.internal.compiler.lookup.*;
21 import org.eclipse.jdt.internal.compiler.parser.*;
22 import org.eclipse.jdt.internal.compiler.problem.*;
24 public class TypeDeclaration
26 implements ProblemSeverities, ReferenceContext {
28 public static final char[] ANONYMOUS_EMPTY_NAME = new char[] {};
30 public int modifiers = AccDefault;
31 public int modifiersSourceStart;
32 public Annotation[] annotations;
34 public TypeReference superclass;
35 public TypeReference[] superInterfaces;
36 public FieldDeclaration[] fields;
37 public AbstractMethodDeclaration[] methods;
38 public TypeDeclaration[] memberTypes;
39 public SourceTypeBinding binding;
40 public ClassScope scope;
41 public MethodScope initializerScope;
42 public MethodScope staticInitializerScope;
43 public boolean ignoreFurtherInvestigation = false;
44 public int maxFieldCount;
45 public int declarationSourceStart;
46 public int declarationSourceEnd;
48 public int bodyEnd; // doesn't include the trailing comment if any.
49 protected boolean hasBeenGenerated = false;
50 public CompilationResult compilationResult;
51 public MethodDeclaration[] missingAbstractMethods;
52 public Javadoc javadoc;
54 public QualifiedAllocationExpression allocation; // for anonymous only
55 public TypeDeclaration enclosingType; // for member types only
57 public FieldBinding enumValuesSyntheticfield; // for enum
60 public TypeParameter[] typeParameters;
62 public TypeDeclaration(CompilationResult compilationResult){
63 this.compilationResult = compilationResult;
67 * We cause the compilation task to abort to a given extent.
69 public void abort(int abortLevel, IProblem problem) {
72 case AbortCompilation :
73 throw new AbortCompilation(this.compilationResult, problem);
74 case AbortCompilationUnit :
75 throw new AbortCompilationUnit(this.compilationResult, problem);
77 throw new AbortMethod(this.compilationResult, problem);
79 throw new AbortType(this.compilationResult, problem);
83 * This method is responsible for adding a <clinit> method declaration to the type method collections.
84 * Note that this implementation is inserting it in first place (as VAJ or javac), and that this
85 * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as
86 * the latter will have to reset the constant pool state accordingly (if it was added first, it does
87 * not need to preserve some of the method specific cached entries since this will be the first method).
88 * inserts the clinit method declaration in the first position.
90 * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int)
92 public final void addClinit() {
94 //see comment on needClassInitMethod
95 if (needClassInitMethod()) {
97 AbstractMethodDeclaration[] methodDeclarations;
98 if ((methodDeclarations = this.methods) == null) {
100 methodDeclarations = new AbstractMethodDeclaration[1];
102 length = methodDeclarations.length;
106 (methodDeclarations = new AbstractMethodDeclaration[length + 1]),
110 Clinit clinit = new Clinit(this.compilationResult);
111 methodDeclarations[0] = clinit;
112 // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits)
113 clinit.declarationSourceStart = clinit.sourceStart = sourceStart;
114 clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd;
115 clinit.bodyEnd = sourceEnd;
116 this.methods = methodDeclarations;
121 * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding.
122 * It is used to report errors for missing abstract methods.
124 public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) {
125 TypeBinding[] argumentTypes = methodBinding.parameters;
126 int argumentsLength = argumentTypes.length;
128 MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult);
129 methodDeclaration.selector = methodBinding.selector;
130 methodDeclaration.sourceStart = sourceStart;
131 methodDeclaration.sourceEnd = sourceEnd;
132 methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract;
134 if (argumentsLength > 0) {
135 String baseName = "arg";//$NON-NLS-1$
136 Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]);
137 for (int i = argumentsLength; --i >= 0;) {
138 arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault);
142 //adding the constructor in the methods list
143 if (this.missingAbstractMethods == null) {
144 this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration };
146 MethodDeclaration[] newMethods;
148 this.missingAbstractMethods,
150 newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1],
152 this.missingAbstractMethods.length);
153 newMethods[0] = methodDeclaration;
154 this.missingAbstractMethods = newMethods;
157 //============BINDING UPDATE==========================
158 methodDeclaration.binding = new MethodBinding(
159 methodDeclaration.modifiers, //methodDeclaration
160 methodBinding.selector,
161 methodBinding.returnType,
162 argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
163 methodBinding.thrownExceptions, //exceptions
164 binding); //declaringClass
166 methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true);
167 methodDeclaration.bindArguments();
169 /* if (binding.methods == null) {
170 binding.methods = new MethodBinding[] { methodDeclaration.binding };
172 MethodBinding[] newMethods;
176 newMethods = new MethodBinding[binding.methods.length + 1],
178 binding.methods.length);
179 newMethods[0] = methodDeclaration.binding;
180 binding.methods = newMethods;
182 //===================================================
184 return methodDeclaration;
188 * Flow analysis for a local innertype
191 public FlowInfo analyseCode(
192 BlockScope currentScope,
193 FlowContext flowContext,
196 if (ignoreFurtherInvestigation)
199 if (flowInfo.isReachable()) {
200 bits |= IsReachableMASK;
201 LocalTypeBinding localType = (LocalTypeBinding) binding;
202 localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
204 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
205 updateMaxFieldCount(); // propagate down the max field count
206 internalAnalyseCode(flowContext, flowInfo);
207 } catch (AbortType e) {
208 this.ignoreFurtherInvestigation = true;
214 * Flow analysis for a member innertype
217 public void analyseCode(ClassScope enclosingClassScope) {
219 if (ignoreFurtherInvestigation)
222 // propagate down the max field count
223 updateMaxFieldCount();
224 internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
225 } catch (AbortType e) {
226 this.ignoreFurtherInvestigation = true;
231 * Flow analysis for a local member innertype
234 public void analyseCode(
235 ClassScope currentScope,
236 FlowContext flowContext,
239 if (ignoreFurtherInvestigation)
242 if (flowInfo.isReachable()) {
243 bits |= IsReachableMASK;
244 LocalTypeBinding localType = (LocalTypeBinding) binding;
245 localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
247 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
248 updateMaxFieldCount(); // propagate down the max field count
249 internalAnalyseCode(flowContext, flowInfo);
250 } catch (AbortType e) {
251 this.ignoreFurtherInvestigation = true;
256 * Flow analysis for a package member type
259 public void analyseCode(CompilationUnitScope unitScope) {
261 if (ignoreFurtherInvestigation)
264 internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
265 } catch (AbortType e) {
266 this.ignoreFurtherInvestigation = true;
271 * Check for constructor vs. method with no return type.
272 * Answers true if at least one constructor is defined
274 public boolean checkConstructors(Parser parser) {
276 //if a constructor has not the name of the type,
277 //convert it into a method with 'null' as its return type
278 boolean hasConstructor = false;
279 if (methods != null) {
280 for (int i = methods.length; --i >= 0;) {
281 AbstractMethodDeclaration am;
282 if ((am = methods[i]).isConstructor()) {
283 if (!CharOperation.equals(am.selector, name)) {
284 // the constructor was in fact a method with no return type
285 // unless an explicit constructor call was supplied
286 ConstructorDeclaration c = (ConstructorDeclaration) am;
287 if (c.constructorCall == null || c.constructorCall.isImplicitSuper()) { //changed to a method
288 MethodDeclaration m = parser.convertToMethodDeclaration(c, this.compilationResult);
292 if (this.kind() == IGenericType.INTERFACE_DECL) {
293 // report the problem and continue the parsing
294 parser.problemReporter().interfaceCannotHaveConstructors(
295 (ConstructorDeclaration) am);
297 hasConstructor = true;
302 return hasConstructor;
305 public CompilationResult compilationResult() {
307 return this.compilationResult;
310 public ConstructorDeclaration createDefaultConstructor(
311 boolean needExplicitConstructorCall,
312 boolean needToInsert) {
314 //Add to method'set, the default constuctor that just recall the
315 //super constructor with no arguments
316 //The arguments' type will be positionned by the TC so just use
317 //the default int instead of just null (consistency purpose)
320 ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult);
321 constructor.isDefaultConstructor = true;
322 constructor.selector = this.name;
323 if (modifiers != AccDefault) {
324 constructor.modifiers =
325 (((this.bits & ASTNode.IsMemberTypeMASK) != 0) && (modifiers & AccPrivate) != 0)
327 : modifiers & AccVisibilityMASK;
330 //if you change this setting, please update the
331 //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method
332 constructor.declarationSourceStart = constructor.sourceStart = sourceStart;
333 constructor.declarationSourceEnd =
334 constructor.sourceEnd = constructor.bodyEnd = sourceEnd;
336 //the super call inside the constructor
337 if (needExplicitConstructorCall) {
338 constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
339 constructor.constructorCall.sourceStart = sourceStart;
340 constructor.constructorCall.sourceEnd = sourceEnd;
343 //adding the constructor in the methods list
345 if (methods == null) {
346 methods = new AbstractMethodDeclaration[] { constructor };
348 AbstractMethodDeclaration[] newMethods;
352 newMethods = new AbstractMethodDeclaration[methods.length + 1],
355 newMethods[0] = constructor;
356 methods = newMethods;
362 // anonymous type constructor creation
363 public MethodBinding createDefaultConstructorWithBinding(MethodBinding inheritedConstructorBinding) {
365 //Add to method'set, the default constuctor that just recall the
366 //super constructor with the same arguments
367 String baseName = "$anonymous"; //$NON-NLS-1$
368 TypeBinding[] argumentTypes = inheritedConstructorBinding.parameters;
369 int argumentsLength = argumentTypes.length;
371 ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationResult);
372 cd.selector = new char[] { 'x' }; //no maining
373 cd.sourceStart = sourceStart;
374 cd.sourceEnd = sourceEnd;
375 cd.modifiers = modifiers & AccVisibilityMASK;
376 cd.isDefaultConstructor = true;
378 if (argumentsLength > 0) {
379 Argument[] arguments = (cd.arguments = new Argument[argumentsLength]);
380 for (int i = argumentsLength; --i >= 0;) {
381 arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault);
385 //the super call inside the constructor
386 cd.constructorCall = SuperReference.implicitSuperConstructorCall();
387 cd.constructorCall.sourceStart = sourceStart;
388 cd.constructorCall.sourceEnd = sourceEnd;
390 if (argumentsLength > 0) {
392 args = cd.constructorCall.arguments = new Expression[argumentsLength];
393 for (int i = argumentsLength; --i >= 0;) {
394 args[i] = new SingleNameReference((baseName + i).toCharArray(), 0L);
398 //adding the constructor in the methods list
399 if (methods == null) {
400 methods = new AbstractMethodDeclaration[] { cd };
402 AbstractMethodDeclaration[] newMethods;
406 newMethods = new AbstractMethodDeclaration[methods.length + 1],
410 methods = newMethods;
413 //============BINDING UPDATE==========================
414 cd.binding = new MethodBinding(
415 cd.modifiers, //methodDeclaration
416 argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
417 inheritedConstructorBinding.thrownExceptions, //exceptions
418 binding); //declaringClass
420 cd.scope = new MethodScope(scope, cd, true);
422 cd.constructorCall.resolve(cd.scope);
424 if (binding.methods == null) {
425 binding.methods = new MethodBinding[] { cd.binding };
427 MethodBinding[] newMethods;
431 newMethods = new MethodBinding[binding.methods.length + 1],
433 binding.methods.length);
434 newMethods[0] = cd.binding;
435 binding.methods = newMethods;
437 //===================================================
443 * Find the matching parse node, answers null if nothing found
445 public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
447 if (fieldBinding != null) {
448 for (int i = 0, max = this.fields.length; i < max; i++) {
449 FieldDeclaration fieldDecl;
450 if ((fieldDecl = this.fields[i]).binding == fieldBinding)
458 * Find the matching parse node, answers null if nothing found
460 public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
462 if (memberTypeBinding != null) {
463 for (int i = 0, max = this.memberTypes.length; i < max; i++) {
464 TypeDeclaration memberTypeDecl;
465 if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding)
466 return memberTypeDecl;
473 * Find the matching parse node, answers null if nothing found
475 public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
477 if (methodBinding != null) {
478 for (int i = 0, max = this.methods.length; i < max; i++) {
479 AbstractMethodDeclaration methodDecl;
481 if ((methodDecl = this.methods[i]).binding == methodBinding)
489 * Finds the matching type amoung this type's member types.
490 * Returns null if no type with this name is found.
491 * The type name is a compound name relative to this type
492 * eg. if this type is X and we're looking for Y.X.A.B
493 * then a type name would be {X, A, B}
495 public TypeDeclaration declarationOfType(char[][] typeName) {
497 int typeNameLength = typeName.length;
498 if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
501 if (typeNameLength == 1) {
504 char[][] subTypeName = new char[typeNameLength - 1][];
505 System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1);
506 for (int i = 0; i < this.memberTypes.length; i++) {
507 TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName);
508 if (typeDecl != null) {
516 * Generic bytecode generation for type
518 public void generateCode(ClassFile enclosingClassFile) {
520 if (hasBeenGenerated)
522 hasBeenGenerated = true;
523 if (ignoreFurtherInvestigation) {
526 ClassFile.createProblemType(
528 scope.referenceCompilationUnit().compilationResult);
532 // create the result for a compiled type
533 ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
534 // generate all fiels
535 classFile.addFieldInfos();
537 // record the inner type inside its own .class file to be able
538 // to generate inner classes attributes
539 if (binding.isMemberType())
540 classFile.recordEnclosingTypeAttributes(binding);
541 if (binding.isLocalType()) {
542 enclosingClassFile.recordNestedLocalAttribute(binding);
543 classFile.recordNestedLocalAttribute(binding);
545 if (memberTypes != null) {
546 for (int i = 0, max = memberTypes.length; i < max; i++) {
547 // record the inner type inside its own .class file to be able
548 // to generate inner classes attributes
549 classFile.recordNestedMemberAttribute(memberTypes[i].binding);
550 memberTypes[i].generateCode(scope, classFile);
553 // generate all methods
554 classFile.setForMethodInfos();
555 if (methods != null) {
556 for (int i = 0, max = methods.length; i < max; i++) {
557 methods[i].generateCode(scope, classFile);
560 // generate all synthetic and abstract methods
561 classFile.addSpecialMethods();
563 if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
564 throw new AbortType(scope.referenceCompilationUnit().compilationResult, null);
567 // finalize the compiled type result
568 classFile.addAttributes();
569 scope.referenceCompilationUnit().compilationResult.record(
570 binding.constantPoolName(),
572 } catch (AbortType e) {
575 ClassFile.createProblemType(
577 scope.referenceCompilationUnit().compilationResult);
582 * Bytecode generation for a local inner type (API as a normal statement code gen)
584 public void generateCode(BlockScope blockScope, CodeStream codeStream) {
586 if ((this.bits & IsReachableMASK) == 0) {
589 if (hasBeenGenerated) return;
590 int pc = codeStream.position;
591 if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
592 generateCode(codeStream.classFile);
593 codeStream.recordPositionsFrom(pc, this.sourceStart);
597 * Bytecode generation for a member inner type
599 public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
601 if (hasBeenGenerated) return;
602 if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
603 generateCode(enclosingClassFile);
607 * Bytecode generation for a package member
609 public void generateCode(CompilationUnitScope unitScope) {
611 generateCode((ClassFile) null);
614 public boolean hasErrors() {
615 return this.ignoreFurtherInvestigation;
619 * Common flow analysis for all types
622 public void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
624 if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
625 if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
626 scope.problemReporter().unusedPrivateType(this);
630 InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, initializerScope);
631 InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, staticInitializerScope);
632 FlowInfo nonStaticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
633 FlowInfo staticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
634 if (fields != null) {
635 for (int i = 0, count = fields.length; i < count; i++) {
636 FieldDeclaration field = fields[i];
637 if (field.isStatic()) {
638 /*if (field.isField()){
639 staticInitializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2
641 staticInitializerContext.handledExceptions = AnyException; // tolerate them all, and record them
645 staticInitializerScope,
646 staticInitializerContext,
648 // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
649 // branch, since the previous initializer already got the blame.
650 if (staticFieldInfo == FlowInfo.DEAD_END) {
651 staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
652 staticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
655 /*if (field.isField()){
656 initializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2
658 initializerContext.handledExceptions = AnyException; // tolerate them all, and record them
661 field.analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
662 // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
663 // branch, since the previous initializer already got the blame.
664 if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
665 initializerScope.problemReporter().initializerMustCompleteNormally(field);
666 nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
671 if (memberTypes != null) {
672 for (int i = 0, count = memberTypes.length; i < count; i++) {
673 if (flowContext != null){ // local type
674 memberTypes[i].analyseCode(scope, flowContext, nonStaticFieldInfo.copy().setReachMode(flowInfo.reachMode())); // reset reach mode in case initializers did abrupt completely
676 memberTypes[i].analyseCode(scope);
680 if (methods != null) {
681 UnconditionalFlowInfo outerInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
682 FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
683 for (int i = 0, count = methods.length; i < count; i++) {
684 AbstractMethodDeclaration method = methods[i];
685 if (method.ignoreFurtherInvestigation)
687 if (method.isInitializationMethod()) {
688 if (method.isStatic()) { // <clinit>
691 staticInitializerContext,
692 staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo).setReachMode(flowInfo.reachMode())); // reset reach mode in case initializers did abrupt completely
693 } else { // constructor
694 method.analyseCode(scope, initializerContext, constructorInfo.copy().setReachMode(flowInfo.reachMode())); // reset reach mode in case initializers did abrupt completely
696 } else { // regular method
697 method.analyseCode(scope, null, flowInfo.copy());
701 // enable enum support ?
702 if (this.binding.isEnum()) {
703 this.enumValuesSyntheticfield = this.binding.addSyntheticFieldForEnumValues();
708 if ((modifiers & AccInterface) != 0) {
709 if ((modifiers & AccAnnotation) != 0)
710 return IGenericType.ANNOTATION_TYPE_DECL;
711 return IGenericType.INTERFACE_DECL;
712 } else if ((modifiers & AccEnum) != 0)
713 return IGenericType.ENUM_DECL;
714 return IGenericType.CLASS_DECL;
718 * Access emulation for a local type
719 * force to emulation of access to direct enclosing instance.
720 * By using the initializer scope, we actually only request an argument emulation, the
721 * field is not added until actually used. However we will force allocations to be qualified
722 * with an enclosing instance.
725 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
727 if (!flowInfo.isReachable()) return;
728 NestedTypeBinding nestedType = (NestedTypeBinding) binding;
730 MethodScope methodScope = currentScope.methodScope();
731 if (!methodScope.isStatic && !methodScope.isConstructorCall){
733 nestedType.addSyntheticArgumentAndField(binding.enclosingType());
735 // add superclass enclosing instance arg for anonymous types (if necessary)
736 if (binding.isAnonymousType()) {
737 ReferenceBinding superclassBinding = (ReferenceBinding)binding.superclass.erasure();
738 if (superclassBinding.enclosingType() != null && !superclassBinding.isStatic()) {
739 if (!superclassBinding.isLocalType()
740 || ((NestedTypeBinding)superclassBinding).getSyntheticField(superclassBinding.enclosingType(), true) != null){
742 nestedType.addSyntheticArgument(superclassBinding.enclosingType());
749 * Access emulation for a local member type
750 * force to emulation of access to direct enclosing instance.
751 * By using the initializer scope, we actually only request an argument emulation, the
752 * field is not added until actually used. However we will force allocations to be qualified
753 * with an enclosing instance.
755 * Local member cannot be static.
757 public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope, FlowInfo flowInfo) {
759 if (!flowInfo.isReachable()) return;
760 NestedTypeBinding nestedType = (NestedTypeBinding) binding;
761 nestedType.addSyntheticArgumentAndField(binding.enclosingType());
765 * A <clinit> will be requested as soon as static fields or assertions are present. It will be eliminated during
766 * classfile creation if no bytecode was actually produced based on some optimizations/compiler settings.
768 public final boolean needClassInitMethod() {
770 // always need a <clinit> when assertions are present
771 if ((this.bits & AddAssertionMASK) != 0)
776 if (kind() == IGenericType.INTERFACE_DECL)
777 return true; // fields are implicitly statics
778 for (int i = fields.length; --i >= 0;) {
779 FieldDeclaration field = fields[i];
780 //need to test the modifier directly while there is no binding yet
781 if ((field.modifiers & AccStatic) != 0)
782 return true; // TODO (philippe) shouldn't it check whether field is initializer or has some initial value ?
783 if (field.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT)
789 public void parseMethod(Parser parser, CompilationUnitDeclaration unit) {
791 //connect method bodies
792 if (unit.ignoreMethodBodies)
796 if (memberTypes != null) {
797 int length = memberTypes.length;
798 for (int i = 0; i < length; i++)
799 memberTypes[i].parseMethod(parser, unit);
803 if (methods != null) {
804 int length = methods.length;
805 for (int i = 0; i < length; i++) {
806 methods[i].parseStatements(parser, unit);
811 if (fields != null) {
812 int length = fields.length;
813 for (int i = 0; i < length; i++) {
814 final FieldDeclaration fieldDeclaration = fields[i];
815 switch(fieldDeclaration.getKind()) {
816 case AbstractVariableDeclaration.INITIALIZER:
817 ((Initializer) fieldDeclaration).parseStatements(parser, this, unit);
824 public StringBuffer print(int indent, StringBuffer output) {
826 if ((this.bits & IsAnonymousTypeMASK) == 0) {
827 printIndent(indent, output);
828 printHeader(0, output);
830 return printBody(indent, output);
833 public StringBuffer printBody(int indent, StringBuffer output) {
835 output.append(" {"); //$NON-NLS-1$
836 if (memberTypes != null) {
837 for (int i = 0; i < memberTypes.length; i++) {
838 if (memberTypes[i] != null) {
840 memberTypes[i].print(indent + 1, output);
844 if (fields != null) {
845 for (int fieldI = 0; fieldI < fields.length; fieldI++) {
846 if (fields[fieldI] != null) { // TODO (olivier) should improve to deal with enumconstants using ',' separator
848 fields[fieldI].print(indent + 1, output);
852 if (methods != null) {
853 for (int i = 0; i < methods.length; i++) {
854 if (methods[i] != null) {
856 methods[i].print(indent + 1, output);
861 return printIndent(indent, output).append('}');
864 public StringBuffer printHeader(int indent, StringBuffer output) {
866 printModifiers(this.modifiers, output);
867 if (this.annotations != null) printAnnotations(this.annotations, output);
870 case IGenericType.CLASS_DECL :
871 output.append("class "); //$NON-NLS-1$
873 case IGenericType.INTERFACE_DECL :
874 output.append("interface "); //$NON-NLS-1$
876 case IGenericType.ENUM_DECL :
877 output.append("enum "); //$NON-NLS-1$
879 case IGenericType.ANNOTATION_TYPE_DECL :
880 output.append("@interface "); //$NON-NLS-1$
884 if (typeParameters != null) {
885 output.append("<");//$NON-NLS-1$
886 for (int i = 0; i < typeParameters.length; i++) {
887 if (i > 0) output.append( ", "); //$NON-NLS-1$
888 typeParameters[i].print(0, output);
890 output.append(">");//$NON-NLS-1$
892 if (superclass != null) {
893 output.append(" extends "); //$NON-NLS-1$
894 superclass.print(0, output);
896 if (superInterfaces != null && superInterfaces.length > 0) {
898 case IGenericType.CLASS_DECL :
899 case IGenericType.ENUM_DECL :
900 output.append(" implements "); //$NON-NLS-1$
902 case IGenericType.INTERFACE_DECL :
903 case IGenericType.ANNOTATION_TYPE_DECL :
904 output.append(" extends "); //$NON-NLS-1$
907 for (int i = 0; i < superInterfaces.length; i++) {
908 if (i > 0) output.append( ", "); //$NON-NLS-1$
909 superInterfaces[i].print(0, output);
915 public StringBuffer printStatement(int tab, StringBuffer output) {
916 return print(tab, output);
921 public void resolve() {
922 SourceTypeBinding sourceType = this.binding;
923 if (sourceType == null) {
924 this.ignoreFurtherInvestigation = true;
928 resolveAnnotations(this.staticInitializerScope, this.annotations, sourceType);
930 if ((this.bits & UndocumentedEmptyBlockMASK) != 0) {
931 this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd);
933 boolean needSerialVersion =
934 this.scope.environment().options.getSeverity(CompilerOptions.MissingSerialVersion) != ProblemSeverities.Ignore
935 && sourceType.isClass()
936 && !sourceType.isAbstract()
937 && sourceType.findSuperTypeErasingTo(T_JavaIoSerializable, false /*Serializable is not a class*/) != null;
939 if (this.typeParameters != null && scope.getJavaLangThrowable().isSuperclassOf(sourceType)) {
940 this.scope.problemReporter().genericTypeCannotExtendThrowable(this);
942 this.maxFieldCount = 0;
943 int lastVisibleFieldID = -1;
944 boolean hasEnumConstants = false;
945 boolean hasEnumConstantsWithoutBody = false;
946 if (this.memberTypes != null) {
947 for (int i = 0, count = this.memberTypes.length; i < count; i++) {
948 this.memberTypes[i].resolve(this.scope);
951 if (this.fields != null) {
952 for (int i = 0, count = this.fields.length; i < count; i++) {
953 FieldDeclaration field = this.fields[i];
954 switch(field.getKind()) {
955 case AbstractVariableDeclaration.ENUM_CONSTANT:
956 hasEnumConstants = true;
957 if (!(field.initialization instanceof QualifiedAllocationExpression))
958 hasEnumConstantsWithoutBody = true;
959 case AbstractVariableDeclaration.FIELD:
960 FieldBinding fieldBinding = field.binding;
961 if (fieldBinding == null) {
962 // still discover secondary errors
963 if (field.initialization != null) field.initialization.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
964 this.ignoreFurtherInvestigation = true;
967 if (needSerialVersion
968 && ((fieldBinding.modifiers & (AccStatic | AccFinal)) == (AccStatic | AccFinal))
969 && CharOperation.equals(TypeConstants.SERIALVERSIONUID, fieldBinding.name)
970 && BaseTypes.LongBinding == fieldBinding.type) {
971 needSerialVersion = false;
973 this.maxFieldCount++;
974 lastVisibleFieldID = field.binding.id;
977 case AbstractVariableDeclaration.INITIALIZER:
978 ((Initializer) field).lastVisibleFieldID = lastVisibleFieldID + 1;
981 field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
984 if (needSerialVersion) {
985 this.scope.problemReporter().missingSerialVersion(this);
987 // check extends/implements for annotation type
988 if (kind() == IGenericType.ANNOTATION_TYPE_DECL) {
989 if (this.superclass != null) {
990 this.scope.problemReporter().annotationTypeDeclarationCannotHaveSuperclass(this);
992 if (this.superInterfaces != null) {
993 this.scope.problemReporter().annotationTypeDeclarationCannotHaveSuperinterfaces(this);
996 // check enum abstract methods
997 if (kind() == IGenericType.ENUM_DECL && this.binding.isAbstract()) {
998 if (!hasEnumConstants || hasEnumConstantsWithoutBody) {
999 for (int i = 0, count = this.methods.length; i < count; i++) {
1000 if (this.methods[i].isAbstract()) {
1001 this.scope.problemReporter().enumAbstractMethodMustBeImplemented(this.methods[i]);
1006 int missingAbstractMethodslength = this.missingAbstractMethods == null ? 0 : this.missingAbstractMethods.length;
1007 int methodsLength = this.methods == null ? 0 : this.methods.length;
1008 if ((methodsLength + missingAbstractMethodslength) > 0xFFFF) {
1009 this.scope.problemReporter().tooManyMethods(this);
1012 if (this.methods != null) {
1013 for (int i = 0, count = this.methods.length; i < count; i++) {
1014 this.methods[i].resolve(this.scope);
1018 if (this.javadoc != null) {
1019 if (this.scope != null) {
1020 this.javadoc.resolve(this.scope);
1022 } else if (sourceType != null && !sourceType.isLocalType()) {
1023 this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, sourceType.modifiers);
1026 } catch (AbortType e) {
1027 this.ignoreFurtherInvestigation = true;
1032 public void resolve(BlockScope blockScope) {
1033 // local type declaration
1035 // need to build its scope first and proceed with binding's creation
1036 if ((this.bits & IsAnonymousTypeMASK) == 0) blockScope.addLocalType(this);
1038 if (binding != null) {
1039 // remember local types binding for innerclass emulation propagation
1040 blockScope.referenceCompilationUnit().record((LocalTypeBinding)binding);
1042 // binding is not set if the receiver could not be created
1044 updateMaxFieldCount();
1048 public void resolve(ClassScope upperScope) {
1049 // member scopes are already created
1050 // request the construction of a binding if local member type
1052 if (binding != null && binding instanceof LocalTypeBinding) {
1053 // remember local types binding for innerclass emulation propagation
1054 upperScope.referenceCompilationUnit().record((LocalTypeBinding)binding);
1057 updateMaxFieldCount();
1060 public void resolve(CompilationUnitScope upperScope) {
1061 // top level : scope are already created
1064 updateMaxFieldCount();
1067 public void tagAsHavingErrors() {
1068 ignoreFurtherInvestigation = true;
1073 * Iteration for a package member type
1076 public void traverse(
1078 CompilationUnitScope unitScope) {
1080 if (ignoreFurtherInvestigation)
1083 if (visitor.visit(this, unitScope)) {
1084 if (this.annotations != null) {
1085 int annotationsLength = this.annotations.length;
1086 for (int i = 0; i < annotationsLength; i++)
1087 this.annotations[i].traverse(visitor, scope);
1089 if (this.superclass != null)
1090 this.superclass.traverse(visitor, scope);
1091 if (this.superInterfaces != null) {
1092 int length = this.superInterfaces.length;
1093 for (int i = 0; i < length; i++)
1094 this.superInterfaces[i].traverse(visitor, scope);
1096 if (this.typeParameters != null) {
1097 int length = this.typeParameters.length;
1098 for (int i = 0; i < length; i++) {
1099 this.typeParameters[i].traverse(visitor, scope);
1102 if (this.memberTypes != null) {
1103 int length = this.memberTypes.length;
1104 for (int i = 0; i < length; i++)
1105 this.memberTypes[i].traverse(visitor, scope);
1107 if (this.fields != null) {
1108 int length = this.fields.length;
1109 for (int i = 0; i < length; i++) {
1110 FieldDeclaration field;
1111 if ((field = this.fields[i]).isStatic()) {
1112 field.traverse(visitor, staticInitializerScope);
1114 field.traverse(visitor, initializerScope);
1118 if (this.methods != null) {
1119 int length = this.methods.length;
1120 for (int i = 0; i < length; i++)
1121 this.methods[i].traverse(visitor, scope);
1124 visitor.endVisit(this, unitScope);
1125 } catch (AbortType e) {
1131 * Iteration for a local innertype
1134 public void traverse(ASTVisitor visitor, BlockScope blockScope) {
1135 if (ignoreFurtherInvestigation)
1138 if (visitor.visit(this, blockScope)) {
1139 if (this.annotations != null) {
1140 int annotationsLength = this.annotations.length;
1141 for (int i = 0; i < annotationsLength; i++)
1142 this.annotations[i].traverse(visitor, scope);
1144 if (this.superclass != null)
1145 this.superclass.traverse(visitor, scope);
1146 if (this.superInterfaces != null) {
1147 int length = this.superInterfaces.length;
1148 for (int i = 0; i < length; i++)
1149 this.superInterfaces[i].traverse(visitor, scope);
1151 if (this.typeParameters != null) {
1152 int length = this.typeParameters.length;
1153 for (int i = 0; i < length; i++) {
1154 this.typeParameters[i].traverse(visitor, scope);
1157 if (this.memberTypes != null) {
1158 int length = this.memberTypes.length;
1159 for (int i = 0; i < length; i++)
1160 this.memberTypes[i].traverse(visitor, scope);
1162 if (this.fields != null) {
1163 int length = this.fields.length;
1164 for (int i = 0; i < length; i++) {
1165 FieldDeclaration field;
1166 if ((field = this.fields[i]).isStatic()) {
1167 // local type cannot have static fields
1169 field.traverse(visitor, initializerScope);
1173 if (this.methods != null) {
1174 int length = this.methods.length;
1175 for (int i = 0; i < length; i++)
1176 this.methods[i].traverse(visitor, scope);
1179 visitor.endVisit(this, blockScope);
1180 } catch (AbortType e) {
1186 * Iteration for a member innertype
1189 public void traverse(ASTVisitor visitor, ClassScope classScope) {
1190 if (ignoreFurtherInvestigation)
1193 if (visitor.visit(this, classScope)) {
1194 if (this.annotations != null) {
1195 int annotationsLength = this.annotations.length;
1196 for (int i = 0; i < annotationsLength; i++)
1197 this.annotations[i].traverse(visitor, scope);
1199 if (this.superclass != null)
1200 this.superclass.traverse(visitor, scope);
1201 if (this.superInterfaces != null) {
1202 int length = this.superInterfaces.length;
1203 for (int i = 0; i < length; i++)
1204 this.superInterfaces[i].traverse(visitor, scope);
1206 if (this.typeParameters != null) {
1207 int length = this.typeParameters.length;
1208 for (int i = 0; i < length; i++) {
1209 this.typeParameters[i].traverse(visitor, scope);
1212 if (this.memberTypes != null) {
1213 int length = this.memberTypes.length;
1214 for (int i = 0; i < length; i++)
1215 this.memberTypes[i].traverse(visitor, scope);
1217 if (this.fields != null) {
1218 int length = this.fields.length;
1219 for (int i = 0; i < length; i++) {
1220 FieldDeclaration field;
1221 if ((field = this.fields[i]).isStatic()) {
1222 field.traverse(visitor, staticInitializerScope);
1224 field.traverse(visitor, initializerScope);
1228 if (this.methods != null) {
1229 int length = this.methods.length;
1230 for (int i = 0; i < length; i++)
1231 this.methods[i].traverse(visitor, scope);
1234 visitor.endVisit(this, classScope);
1235 } catch (AbortType e) {
1241 * MaxFieldCount's computation is necessary so as to reserve space for
1242 * the flow info field portions. It corresponds to the maximum amount of
1243 * fields this class or one of its innertypes have.
1245 * During name resolution, types are traversed, and the max field count is recorded
1246 * on the outermost type. It is then propagated down during the flow analysis.
1248 * This method is doing either up/down propagation.
1250 void updateMaxFieldCount() {
1252 if (binding == null)
1253 return; // error scenario
1254 TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
1255 if (maxFieldCount > outerMostType.maxFieldCount) {
1256 outerMostType.maxFieldCount = maxFieldCount; // up
1258 maxFieldCount = outerMostType.maxFieldCount; // down